/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2011 The Boeing Company
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors:
 *  Gary Pei <guangyu.pei@boeing.com>
 *  kwong yin <kwong-sang.yin@boeing.com>
 *  Tom Henderson <thomas.r.henderson@boeing.com>
 *  Stephane Kamga <stephanekamga2003@yahoo.fr>
 */
#include "ns3/simulator.h"
#include "ns3/lr-wpan-mac.h"
#include "ns3/log.h"
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/lr-wpan-csmaca.h"
#include "ns3/lr-wpan-phy.h"
#include "ns3/mac16-address.h"
#include "ns3/mac64-address.h"
#include "ns3/lr-wpan-transactionList.h"
#include "ns3/lr-wpan-associated-device.h"

NS_LOG_COMPONENT_DEFINE ("LrWpanMac");

#undef NS_LOG_APPEND_CONTEXT
#define NS_LOG_APPEND_CONTEXT                                   \
		std::clog << "[address " << m_macPIBattributes.macShortAddress << "] ";

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (LrWpanMac);

const uint32_t LrWpanMac::aMinMPDUOverhead = 9; // Table 85
const uint64_t LrWpanMac::aUnitBackoffPeriod = 20;		//number of symbols  used by the CSMA-CA algorithm
const uint64_t LrWpanMac::m_aMaxBeaconOverhead= 75;



TypeId
LrWpanMac::GetTypeId (void)
{
	static TypeId tid = TypeId ("ns3::LrWpanMac")
    						.SetParent<Object> ()
    						.AddConstructor<LrWpanMac> ()
    						//		.AddAttribute ("PanId", "16-bit identifier of the associated PAN",
    						//				UintegerValue (),
    						//				MakeUintegerAccessor (&LrWpanMac::m_macPIBattributes.macPANId),
    						//				MakeUintegerChecker<uint16_t> ())
    						.AddTraceSource ("MacTx",
    								"Trace source indicating a packet has arrived for transmission by this device",
    								MakeTraceSourceAccessor (&LrWpanMac::m_macTxTrace))
    								.AddTraceSource ("MacTxDrop",
    										"Trace source indicating a packet has been dropped by the device before transmission",
    										MakeTraceSourceAccessor (&LrWpanMac::m_macTxDropTrace))
    										.AddTraceSource ("MacPromiscRx",
    												"A packet has been received by this device, has been passed up from the physical layer "
    												"and is being forwarded up the local protocol stack.  This is a promiscuous trace,",
    												MakeTraceSourceAccessor (&LrWpanMac::m_macPromiscRxTrace))
    												.AddTraceSource ("MacRx",
    														"A packet has been received by this device, has been passed up from the physical layer "
    														"and is being forwarded up the local protocol stack.  This is a non-promiscuous trace,",
    														MakeTraceSourceAccessor (&LrWpanMac::m_macRxTrace))
    														.AddTraceSource ("MacRxDrop",
    																"Trace source indicating a packet was received, but dropped before being forwarded up the stack",
    																MakeTraceSourceAccessor (&LrWpanMac::m_macRxDropTrace))
    																.AddTraceSource ("Sniffer",
    																		"Trace source simulating a non-promiscuous packet sniffer attached to the device",
    																		MakeTraceSourceAccessor (&LrWpanMac::m_snifferTrace))
    																		.AddTraceSource ("PromiscSniffer",
    																				"Trace source simulating a promiscuous packet sniffer attached to the device",
    																				MakeTraceSourceAccessor (&LrWpanMac::m_promiscSnifferTrace))
    																				.AddTraceSource ("MacState",
    																						"The state of LrWpan Mac",
    																						MakeTraceSourceAccessor (&LrWpanMac::m_macStateLogger))
    																						;
	return tid;
}

LrWpanMac::LrWpanMac ()
{

	ChangeMacState (MAC_IDLE);
	ResetMacPIBattributes();
	m_userCase = Mlme_No_Case;
	resetUserCase();
	m_macPIBattributes = def_MacPIBattributes;
	m_selfExt = Mac64Address::Allocate ();
}

LrWpanMac::~LrWpanMac ()
{
}

void
LrWpanMac::DoDispose ()
{
	if (m_csmaCa != 0)
	{
		m_csmaCa->Dispose ();
		m_csmaCa = 0;
	}
	m_txPkt = 0;
	for (uint32_t i = 0; i < m_txQueue.size (); i++)
	{
		m_txQueue[i]->txQPkt = 0;
		delete m_txQueue[i];
	}
	m_txQueue.clear ();
	m_phy = 0;
	m_mcpsDataIndicationCallback = MakeNullCallback< void, McpsDataIndicationParams, Ptr<Packet> > ();
	m_mcpsDataConfirmCallback = MakeNullCallback< void, McpsDataConfirmParams > ();
	m_mlmeGetConfirmCallback = MakeNullCallback<void, MlmeGetConfirmParams>();
	m_mlmeSetConfirmCallback = MakeNullCallback<void, MlmeSetConfirmParams>();
	m_mlmeRXEnableConfirmCallback = MakeNullCallback<void, MlmeRXEnableConfirmParams>();
	m_mlmeAssociateConfirmCallback = MakeNullCallback<void, MlmeAssociateConfirmParams>();
	m_mlmeAssociateIndicationCallback = MakeNullCallback<void, MlmeAssociateIndicationParams>();
	m_mlmeCommStatusIndicationCallback = MakeNullCallback<void, MlmeCommStatusIndicationParams>();
	m_mlmePollConfirmCallback =  MakeNullCallback<void, MlmePollConfirmParams>();
	m_mlmeDisassociateConfirmCallback = MakeNullCallback<void, MlmeDisassociateConfirmParams>();
	m_mlmeDisassociateIndicationCallback = MakeNullCallback<void, MlmeDisassociateIndicationParams>();
	m_mlmeStartConfirmCallback = MakeNullCallback<void, MlmeStartConfirmparams>();
}




void
LrWpanMac::SetExtendedAddress (Mac64Address address)
{
	//NS_LOG_FUNCTION (this << address);
	m_selfExt = address;
}

Mac64Address
LrWpanMac::GetExtendedAddress () const
{
	NS_LOG_FUNCTION (this);
	return m_selfExt;
}
void
LrWpanMac::McpsDataRequest (McpsDataRequestParams params, Ptr<Packet> p)
{
	NS_LOG_FUNCTION (this << p);
	McpsDataConfirmParams confirmParams;
	confirmParams.m_msduHandle = params.m_msduHandle;

	LrWpanMacHeader macHdr (LrWpanMacHeader::LRWPAN_MAC_DATA, (uint8_t)m_macPIBattributes.macDSN.GetValue ());
	m_macPIBattributes.macDSN ++;
	if (m_macPIBattributes.macDSN > SequenceNumber16 (255))
	{
		m_macPIBattributes.macDSN = m_macPIBattributes.macDSN - SequenceNumber16 (255);
	}

	if (p->GetSize () > LrWpanPhy::aMaxPhyPacketSize - aMinMPDUOverhead)
	{
		// Note, this is just testing maximum theoretical frame size per the spec
		// The frame could still be too large once headers are put on
		// in which case the phy will reject it instead
		NS_LOG_ERROR (this << " packet too big: " << p->GetSize ());
		confirmParams.m_status = IEEE_802_15_4_FRAME_TOO_LONG;
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}
		else{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}

	if ((params.m_srcAddrMode == NO_PANID_ADDR)
			&& (params.m_dstAddrMode == NO_PANID_ADDR))
	{
		NS_LOG_ERROR (this << " Can not send packet with no Address field" );
		confirmParams.m_status = IEEE_802_15_4_INVALID_ADDRESS;
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}
		else{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}
	switch (params.m_srcAddrMode)
	{
	case NO_PANID_ADDR:
		macHdr.SetSrcAddrMode (params.m_srcAddrMode);
		macHdr.SetNoPanIdComp ();
		break;
	case ADDR_MODE_RESERVED:
		macHdr.SetSrcAddrMode (params.m_srcAddrMode);
		break;
	case SHORT_ADDR:
		macHdr.SetSrcAddrMode (params.m_srcAddrMode);
		macHdr.SetSrcAddrFields (m_macPIBattributes.macPANId, m_macPIBattributes.macShortAddress );
		break;
	case EXT_ADDR:
		macHdr.SetSrcAddrMode (params.m_srcAddrMode);
		macHdr.SetSrcAddrFields (m_macPIBattributes.macPANId, m_selfExt );
		break;
	default:
		NS_LOG_ERROR (this << " Can not send packet with incorrect Source Address mode = " << params.m_srcAddrMode);
		confirmParams.m_status = IEEE_802_15_4_INVALID_ADDRESS;
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}
		else
		{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}

	if ((params.m_dstAddrMode >= NO_PANID_ADDR)
			&& (params.m_dstAddrMode <= EXT_ADDR))
	{
		macHdr.SetDstAddrMode (params.m_dstAddrMode);
		macHdr.SetDstAddrFields (params.m_dstPanId, params.m_dstAddr);
	}
	else
	{
		NS_LOG_ERROR (this << " Can not send packet with incorrect Destination Address mode" << params.m_dstAddrMode);
		confirmParams.m_status = IEEE_802_15_4_INVALID_ADDRESS;
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}else
		{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}
	macHdr.SetSecDisable ();
	//extract the last 3 bits in TxOptions and map to macHdr
	int b0 = params.m_txOptions & 1;
	int b1 = params.m_txOptions & 2;
	int b2 = params.m_txOptions & 4;
	if (b0 == 1)
	{
		macHdr.SetAckReq ();
	}
	else if (b0 == 0)
	{
		macHdr.SetNoAckReq ();
	}
	else
	{
		confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER;
		NS_LOG_ERROR (this << "Incorrect TxOptions bit 0 not 0/1");
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}else{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}

	//if is Slotted CSMA means its beacon enabled
	if (m_csmaCa->isSlottedCsmaCa ())
	{
		if (b1 == 2)
		{
			//TODO:GTS Transmission
		}
		else if (b1 == 0)
		{
			//TODO:CAP Transmission
		}
		else
		{
			NS_LOG_ERROR (this << "Incorrect TxOptions bit 1 not 0/1");
			confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER;
			if (!m_mcpsDataConfirmCallback.IsNull ())
			{
				m_mcpsDataConfirmCallback (confirmParams);
			}
			else{
				NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
			}
			return;
		}
	}
	else
	{
		if (b1 != 0)
		{
			NS_LOG_ERROR (this << "for non-beacon-enables PAN, bit 1 should always be set to 0");
			confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER;
			if (!m_mcpsDataConfirmCallback.IsNull ())
			{
				m_mcpsDataConfirmCallback (confirmParams);
			}
			else{
				NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
			}
			return;
		}
	}

	if (b2 == 4)
	{
		//TODO :indirect tx
	}
	else if (b2 == 0)
	{
		//TODO :direct tx
	}
	else
	{
		NS_LOG_ERROR (this << "Incorrect TxOptions bit 2 not 0/1");
		confirmParams.m_status = IEEE_802_15_4_INVALID_PARAMETER;
		if (!m_mcpsDataConfirmCallback.IsNull ())
		{
			m_mcpsDataConfirmCallback (confirmParams);
		}
		else{
			NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
		}
		return;
	}

	p->AddHeader (macHdr);

	LrWpanMacTrailer macTrailer;
	p->AddTrailer (macTrailer);

	m_macTxTrace (p);
	confirmParams.m_status = IEEE_802_15_4_SUCCESS;
	if (!m_mcpsDataConfirmCallback.IsNull ())
	{
		m_mcpsDataConfirmCallback (confirmParams);
	}
	else{
		NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");
	}

	TxQueueElement *txQElement = new TxQueueElement;
	txQElement->txQMsduHandle = params.m_msduHandle;
	txQElement->txQPkt = p;
	if (m_txQueue.empty ())
	{
		m_txPkt = txQElement->txQPkt->Copy ();
		m_txQueue.push_front (txQElement); // the first packet in the queue is currently worked on
		// Start CCA process for this packet
		Simulator::ScheduleNow (&LrWpanCsmaCa::Start, m_csmaCa);
	}
	else
	{
		// if queue is not empty put this packet at the end of Tx queue
		m_txQueue.push_back (txQElement);
	}
}

void LrWpanMac::SetCsmaCa (Ptr<LrWpanCsmaCa> csmaCa)
{
	m_csmaCa = csmaCa;
}

void LrWpanMac::SetPhy (Ptr<LrWpanPhy> phy)
{
	m_phy = phy;
}

Ptr<LrWpanPhy> LrWpanMac::GetPhy (void)
{
	return m_phy;
}

void
LrWpanMac::SetMcpsDataIndicationCallback (McpsDataIndicationCallback c)
{
	m_mcpsDataIndicationCallback = c;
}

void
LrWpanMac::SetMcpsDataConfirmCallback (McpsDataConfirmCallback c)
{
	m_mcpsDataConfirmCallback = c;
}
void
LrWpanMac::setMlmeSetConfirmCallback(MlmeSetConfirmCallback c)
{
	m_mlmeSetConfirmCallback = c;
}
void
LrWpanMac::setMlmeGetConfirmCallback(MlmeGetConfirmCallback c)
{
	m_mlmeGetConfirmCallback = c;
}
void
LrWpanMac::setMlmeRXEnableConfirmCallback(MlmeRXEnableConfirmCallback c)
{
	m_mlmeRXEnableConfirmCallback = c;
}
void
LrWpanMac::setMlmeAssociateConfirmCallback(MlmeAssociateConfirmCallback c)
{
	m_mlmeAssociateConfirmCallback = c;
}
void
LrWpanMac::setMlmeAssociateIndicationCallback(MlmeAssociateIndicationCallback c)
{
	m_mlmeAssociateIndicationCallback = c;
}
void
LrWpanMac::setMlmeCommStatusIndicationCallback(MlmeCommStatusIndicationCallback c)
{
	m_mlmeCommStatusIndicationCallback = c;
}
void
LrWpanMac::setMlmePollConfirmCallback(MlmePollConfirmCallback c)
{
	m_mlmePollConfirmCallback = c;
}
void
LrWpanMac::setMlmeDisassociateIndicationCallback(MlmeDisassociateIndicationCallback c)
{
	m_mlmeDisassociateIndicationCallback = c;
}
void
LrWpanMac::setMlmeDisassociateConfirmCallback(MlmeDisassociateConfirmCallback c)
{
	m_mlmeDisassociateConfirmCallback = c;
}
void
LrWpanMac::setMlmeStartConfirmCallback(MlmeStartConfirmCallback c)
{
	m_mlmeStartConfirmCallback = c;
}
void
LrWpanMac::setMlmeScanConfirmCallback(MlmeScanConfirmCallback c)
{
	m_mlmeScanConfirmCallback = c;
}
void
LrWpanMac::setMlmeOrphanIndicationCallback(MlmeOrphanIndicationCallback c)
{
	m_mlmeOrphanIndicationCallback = c;
}
void
LrWpanMac::PdDataIndication (uint32_t psduLength, Ptr<Packet> p, uint32_t lqi)
{
	NS_LOG_FUNCTION (this << psduLength << p << lqi);

	bool acceptFrame;
	Ptr<Packet> originalPkt = p->Copy (); // because we will strip headers
	acceptFrame = MacFrameFiltering(p->Copy());
	if(!acceptFrame)
	{
		NS_LOG_DEBUG("Packet not for" << m_selfExt);
		return;
	}
	LrWpanMacHeader receivedMacHdr;
	p->RemoveHeader (receivedMacHdr);
	LrWpanMacTrailer receivedMacTrailer;
	p->RemoveTrailer (receivedMacTrailer);
	if(receivedMacHdr.IsSecEnable())
	{
		//todo implement security for the frame
	}
	switch (receivedMacHdr.GetType())
	{
	case LrWpanMacHeader::LRWPAN_MAC_COMMAND:
	{
		uint8_t cmdType;
		p->CopyData(&cmdType,1);	//the command type is saved in the first element of the buffer
		switch (cmdType)
		{
		case 0x01:		//0x01 represent the associate request command
		{
			NS_LOG_FUNCTION(  "association request command received");
			if(m_selfExt != m_macPIBattributes.macCoordExtendedAddress)
			{
				NS_LOG_ERROR("node" << m_selfExt << "is not the coordinator" );
				return;
			}
			uint8_t  pktBuffer[2];
			p->CopyData(pktBuffer,2);
			NS_ASSERT(receivedMacHdr.IsAckReq());
			sendACKnowledgment(&receivedMacHdr);
			m_MlmeAssociateIndicationParams.CapabilityInformation = pktBuffer[1];
			m_MlmeAssociateIndicationParams.DeviceAddress = receivedMacHdr.GetExtSrcAddr();
			if(receivedMacHdr.IsSecEnable())
				m_MlmeAssociateIndicationParams.SecurityLevel = receivedMacHdr.GetSecLevel();
			else
				m_MlmeAssociateIndicationParams.SecurityLevel = 0;
			if((!m_mlmeAssociateIndicationCallback.IsNull()))
				m_mlmeAssociateIndicationCallback(m_MlmeAssociateIndicationParams);
			else
				NS_LOG_ERROR("m_mlmeAssociateIndicationCallback not initialized");
			break;
		}
		case 0x02:			// 0x02 represents an association response
		{
			NS_LOG_FUNCTION("an association response command received");
			NS_ASSERT(receivedMacHdr.IsAckReq());
			sendACKnowledgment(&receivedMacHdr);
			if(m_userCase == Mlme_Associate_Request)
			{
				if(m_DataEvent.IsExpired())
				{
					NS_LOG_ERROR("association Response Command received too late!!");
					m_macRxDropTrace(originalPkt);
				}
				else
				{
					uint8_t buffer[4];
					p->CopyData(buffer,4);
					uint8_t assocBuffer[2];		//this buffer receives the bit composing the address given by the coordinator
					assocBuffer[0] = buffer[1];
					assocBuffer[1] = buffer[2];
					Mac16Address assocAddress;
					assocAddress.CopyFrom(assocBuffer);
					m_MlmeAssociateConfirmParams.AssocShortAddress = assocAddress;
					m_MlmeAssociateConfirmParams.status =(LrWpanMACResultStatus) buffer[3];			//the status returned by the coordinator
					if(receivedMacHdr.IsSecEnable())
						m_MlmeAssociateIndicationParams.SecurityLevel = receivedMacHdr.GetSecLevel();
					else
						m_MlmeAssociateIndicationParams.SecurityLevel = 0;
					//we should set the macPIB value
					//todo how is maccoordshort adress supposed to be set????
					m_macPIBattributes.macCoordExtendedAddress = receivedMacHdr.GetExtSrcAddr();		//in case it was not set before
					m_CmdReceived = true;
					MlmeAssociateRequest(m_MlmeAssociateRequestParams);
				}
			}
			else
			{
				NS_LOG_ERROR("Unexpected Associate Response Command Received by " << m_selfExt);
				m_macRxDropTrace(originalPkt);;
			}
			break;
		}
		case 0x03: //it's a disassociation notification command
		{
			NS_LOG_FUNCTION("disassociation notification command received");
			NS_ASSERT(receivedMacHdr.IsAckReq());
			sendACKnowledgment(&receivedMacHdr);
			uint8_t payload[2];
			p->CopyData(payload,2);
			MlmeDisassociateIndicationParams param;
			//if  this device is not the coordinator
			if(m_selfExt != m_macPIBattributes.macCoordExtendedAddress)
			{
				NS_ASSERT_MSG(payload[1],"not corresponding address in disassociate notification Command");
				m_macPIBattributes.macShortAddress=def_MacPIBattributes.macShortAddress;
				m_macPIBattributes.macCoordExtendedAddress=def_MacPIBattributes.macCoordExtendedAddress;
				m_macPIBattributes.macCoordShortAddress=def_MacPIBattributes.macCoordShortAddress;
				m_macPIBattributes.macPANId=def_MacPIBattributes.macPANId;
				m_macPIBattributes.macAssociatedPANCoord = def_MacPIBattributes.macAssociatedPANCoord;
			}
			else			 //if this node is the coordinator
			{
				NS_ASSERT_MSG(payload[1] == 0x02,"not corresponding address in disassociate notification Command");
				std::list<associateDeviceAddress>::iterator it;
				NS_ASSERT_MSG(this->GetObject<LrWpanAssociatedDevice>(),"LrwpanAssociatedDevice not intialized");
				this->GetObject<LrWpanAssociatedDevice>()->removeAssociateDevice(receivedMacHdr.GetExtSrcAddr(),EXT_ADDR);
			}
			param.DisassociateReason = payload[1];
			if(receivedMacHdr.IsSecEnable())
				param.SecurityLevel = receivedMacHdr.GetSecLevel();
			else
				param.SecurityLevel = 0;
			param.DeviceAddress = receivedMacHdr.GetExtSrcAddr();
			if(!m_mlmeDisassociateIndicationCallback.IsNull())
				m_mlmeDisassociateIndicationCallback(param);
			else
				NS_LOG_ERROR("m_mlmeDisassociateIndication not initialized");
			if(m_userCase == Mlme_Poll_Request)	//in case the packet is received after a poll request this should be added for further case of POllRequest uses
			{
				if(m_DataEvent.IsExpired())
				{
					NS_LOG_ERROR("Data received too Late! " << m_selfExt);
				}
				else{
					//as the packet contained the packet type and is assert to be a data packet all conditions are ok
					m_DataReceived =  true;
					if(receivedMacHdr.IsFrmPend())
						m_framePending = true;
					MlmePollRequest(m_MlmePollRequestParams);
				}
			}
			break;
		}
		case 0x04: // its a data request command frame
		{

			NS_LOG_FUNCTION("data request command received by" << m_selfExt);
			if(receivedMacHdr.IsAckReq())
				sendACKnowledgment(&receivedMacHdr,true);
			Simulator::ScheduleNow(&LrWpanMac::DataResponse, this, receivedMacHdr); //now i should check in my pending list to see if there is a packet pending for the device which send the packet
			break;
		}
		case 0x06: //it's an orphan notification command
		{
			//check if this device is the coordinator of a PAN, if not we drop the packet
			if(m_selfExt == m_macPIBattributes.macCoordExtendedAddress)
			{
				NS_LOG_FUNCTION("orphan notification frame received by " << m_selfExt);
				MlmeOrphanIndicationParams param;
				param.OrphanAddress = receivedMacHdr.GetExtSrcAddr();
				if(receivedMacHdr.IsSecEnable())
					param.SecurityLevel = receivedMacHdr.GetSecLevel();
				else
					param.SecurityLevel = 0;
				if(!m_mlmeOrphanIndicationCallback.IsNull())
					m_mlmeOrphanIndicationCallback(param);
				else
					NS_LOG_ERROR("m_mlmeOrphanIndicationCallback is not initialized");
			}
			else
			{
				m_macRxDropTrace(originalPkt);
			}
			break;
		}
		case 0x08:		//it's a coordinator realignment command
		{
			NS_LOG_FUNCTION("Realignment command frame received");
			NS_ASSERT(receivedMacHdr.IsAckReq());
			sendACKnowledgment(&receivedMacHdr);
			if(m_userCase == Mlme_Scan_Request)
			{
				if(m_orphanEvent.IsRunning())
				{
					uint8_t payload[9];
					p->CopyData(payload,9);
					//we set the macpanID of the orphaned device
					uint16_t panid_lsb = uint16_t(payload[1]);
					uint16_t panid_msb = ((uint16_t)payload[2]) << 8;
					uint16_t panid_result = panid_msb|(panid_lsb);
					m_macPIBattributes.macPANId = panid_result;
					//we set the coordinator short address
					uint8_t addressPayload[2];
					addressPayload[0] = payload[3];
					addressPayload[1] = payload[4];
					m_macPIBattributes.macCoordShortAddress.CopyFrom(addressPayload);
					addressPayload[0] = payload[6];
					addressPayload[1] = payload[7];
					//we set the short address of the device
					m_macPIBattributes.macShortAddress.CopyFrom(addressPayload);
					//we set the page
					//m_tmpPhyPIBattributes.phyCurrentPage = payload[8];
					//Simulator::ScheduleNow(&LrWpanPhy::PlmeSetAttributeRequest,m_phy,phyCurrentPage,&m_tmpPhyPIBattributes);
					//we set the phyCurrentChannel
					m_tmpPhyPIBattributes.phyCurrentChannel = payload[5];
					Simulator::ScheduleNow(&LrWpanPhy::PlmeSetAttributeRequest,m_phy,phyCurrentChannel,&m_tmpPhyPIBattributes);
					//we set the MacCoordExtendedAddress
					m_macPIBattributes.macCoordExtendedAddress = receivedMacHdr.GetExtSrcAddr();
					m_macPIBattributes.macAssociatedPANCoord = true;
					m_CmdReceived = true;
					MlmeScanRequest(m_MlmeScanRequestParams);
					break;
				}
				else
				{
					NS_LOG_ERROR("coordinator realignment command received too late!");
					m_macRxDropTrace(originalPkt);

				}
			}
			{
				NS_LOG_ERROR("Received an unexpected Coordinator realignment Command!");
				m_macRxDropTrace(originalPkt);
			}
			break;
		}
		}
		break;
	}
	case LrWpanMacHeader::LRWPAN_MAC_DATA:
	{
		McpsDataIndicationParams params;
		params.m_dsn = receivedMacHdr.GetSeqNum ();
		params.m_mpduLinkQuality = lqi;
		params.m_srcPanId = receivedMacHdr.GetSrcPanId ();
		params.m_srcAddrMode = receivedMacHdr.GetSrcAddrMode ();
		if (params.m_srcAddrMode == SHORT_ADDR)
		{
			params.m_srcAddr = receivedMacHdr.GetShortSrcAddr ();
		}
		params.m_dstPanId = receivedMacHdr.GetDstPanId ();
		params.m_dstAddrMode = receivedMacHdr.GetDstAddrMode ();
		if (params.m_dstAddrMode == SHORT_ADDR)
		{
			params.m_dstAddr = receivedMacHdr.GetShortDstAddr ();
		}
		if (!m_mcpsDataIndicationCallback.IsNull ())
		{
			m_mcpsDataIndicationCallback (params, p);
		}
		else
		{
			NS_LOG_ERROR (this << " Data Indication Callback not initialized");
		}
		if(m_userCase == Mlme_Poll_Request)
		{
			if(m_DataEvent.IsExpired())
			{
				NS_LOG_ERROR("Data received too Late! " << m_selfExt);
				m_macRxDropTrace(originalPkt);
			}
			else{
				//as the packet contained the packet type and is assert to be a data packet all conditions are ok
				m_DataReceived =  true;
				if(receivedMacHdr.IsFrmPend())
					m_framePending = true;
				MlmePollRequest(m_MlmePollRequestParams);
			}
		}
	/*	else if (condition) {
			//todo to be completed for MCPS cases
		}*/
		break;
	}
	case LrWpanMacHeader::LRWPAN_MAC_ACKNOWLEDGMENT:
	{
		NS_LOG_DEBUG("node" << m_selfExt << " received an ACK ");
		if(m_ACKEvent.IsExpired())
		{
			NS_LOG_ERROR("ACK received too Late!" << m_selfExt);
			m_macRxDropTrace(originalPkt);
		}
		else
		{
			//we signal we received an ack
			m_ACK_received = true;
			switch (m_userCase)
			{
			case Mlme_Associate_Request:
				MlmeAssociateRequest(m_MlmeAssociateRequestParams);
				break;
			case Mlme_Associate_Response:
				MlmeAssociateResponse(m_MlmeAssociateResponseParams);
				break;
			case Mlme_Poll_Request:
			{
				//the frame pending field tell us about the presence of a packet direct to the node in the transaction list
				if(receivedMacHdr.IsFrmPend())
					m_framePending = true;
				MlmePollRequest(m_MlmePollRequestParams);
				break;
			}
			case Mlme_Disassociate_Request:
				MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
				break;
			default:
				break;
			}
		}
		break;
	}
	default:
		break;
	}
	m_promiscSnifferTrace (originalPkt);
}

void
LrWpanMac::PdDataConfirm (LrWpanPhyEnumeration status)
{
	NS_LOG_FUNCTION (this << status << m_txQueue.empty () ? 0 : m_txQueue.size ());
	m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_RX_ON);
	bool wasACK;				// this allow us to know if the pacekt we just sent was an ACK or not
	if (status == IEEE_802_15_4_PHY_SUCCESS || status == IEEE_802_15_4_PHY_UNSPECIFIED)
	{
		// remove the copy of the packet that was just sent
		TxQueueElement *txQElement = m_txQueue.front ();
		//check the type of the packet that was just sent
		LrWpanMacHeader tmpHdr;
		Ptr<Packet> tmpPkt = m_txQueue.front()->txQPkt->Copy();
		tmpPkt = txQElement->txQPkt->Copy();
		tmpPkt->RemoveHeader(tmpHdr);
		tmpHdr.IsAcknowledgment()? wasACK = true : wasACK =  false;
		tmpPkt = 0;
		txQElement->txQPkt = 0;
		delete txQElement;
		m_txQueue.pop_front ();
		ChangeMacState (CHANNEL_IDLE);
		if (!m_txQueue.empty ())
		{
			NS_LOG_DEBUG(m_txQueue.size());
			NS_LOG_FUNCTION ("PdDataConfirm:  start CCA process for next packet");
			// Start CCA process for next packet in the tx queue
			m_txPkt = m_txQueue.front ()->txQPkt->Copy();
			//we check the type of packet we are about to transmit
			Ptr<Packet> tmp = m_txPkt->Copy();
			LrWpanMacHeader tmpHdr;
			tmp->RemoveHeader(tmpHdr);
			if(tmpHdr.IsAcknowledgment())
			{
				//the packet is an acknowledgment no CSMA needed
				double a = (double)(LrWpanPhy::aTurnaroundTime);
				double b = (double)(m_phy->GetDataOrSymbolRate(false));
				Time time2wait = Seconds(a / b);
				Simulator::Schedule(time2wait,&LrWpanMac::SetLrWpanMacState,this,CHANNEL_IDLE);
			}
			else
			{
				Simulator::ScheduleNow (&LrWpanCsmaCa::Start, m_csmaCa);
			}
		}
	}
	if(!wasACK)
	{
		switch (m_userCase)
		{
		case Mlme_Associate_Request:
			MlmeAssociateRequest(m_MlmeAssociateRequestParams);
			break;
		case Mlme_Associate_Response:
			MlmeAssociateResponse(m_MlmeAssociateResponseParams);
			break;
		case Mlme_Disassociate_Request:
			MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
			break;
		case Mlme_Scan_Request:
			MlmeScanRequest(m_MlmeScanRequestParams);
			break;
		case Mlme_Orphan_Response:
			MlmeOrphanResponse(m_MlmeOrphanResponseParams);
			break;
		case Mlme_Poll_Request:
			MlmePollRequest(m_MlmePollRequestParams);
			break;
		default:
			break;
		}
	}
}
void
LrWpanMac::PlmeCcaConfirm (LrWpanPhyEnumeration status)
{
	NS_LOG_FUNCTION (this << status);
	// Direct this call through the csmaCa object
	m_csmaCa->PlmeCcaConfirm (status);
}

void
LrWpanMac::PlmeEdConfirm (LrWpanPhyEnumeration status, uint8_t energyLevel)
{
	NS_LOG_FUNCTION (this << status << energyLevel);

}

void
LrWpanMac::PlmeGetAttributeConfirm (LrWpanPhyEnumeration status,
		LrWpanPibAttributeIdentifier id,
		LrWpanPhyPIBAttributes* attribute)
{
	NS_LOG_FUNCTION (this << status << id << attribute);
	status=PlmeAttributeConfirmStatus;
	memcpy(&m_tmpPhyPIBattributes,attribute,sizeof(m_tmpPhyPIBattributes));
}

void
LrWpanMac::PlmeSetTRXStateConfirm (LrWpanPhyEnumeration status)
{
	NS_LOG_FUNCTION (this << status);
	PlmeAttributeConfirmStatus = status;
	if (status == IEEE_802_15_4_PHY_TX_ON || status == IEEE_802_15_4_PHY_SUCCESS)
	{
		if ((m_txPkt) && (m_lrWpanMacState == SET_PHY_TX_ON))
		{
			m_promiscSnifferTrace (m_txPkt);
			m_snifferTrace (m_txPkt);
			m_phy->PdDataRequest (m_txPkt->GetSize (), m_txPkt);
		}
	}
}

void
LrWpanMac::PlmeSetAttributeConfirm (LrWpanPhyEnumeration status,
		LrWpanPibAttributeIdentifier id)
{
	NS_LOG_FUNCTION (this << status << id);
	PlmeAttributeConfirmStatus = status;
}

void
LrWpanMac::SetLrWpanMacState (LrWpanMacState macState)
{
	NS_LOG_FUNCTION (this << "mac state = " << macState);

	McpsDataConfirmParams confirmParams;

	ChangeMacState (macState);
	if ((m_lrWpanMacState == CHANNEL_IDLE) && (m_txPkt))
	{
		// Channel is idle, set transmitter to TX_ON
		NS_LOG_DEBUG ( this << " channel idle");
		ChangeMacState (SET_PHY_TX_ON);
		m_phy->PlmeSetTRXStateRequest (IEEE_802_15_4_PHY_TX_ON);
	}
	else if ((m_lrWpanMacState == CHANNEL_ACCESS_FAILURE) && (m_txPkt))
	{
		// cannot find a clear channel, drop the current packet.
		NS_LOG_DEBUG ( this << " cannot find clear channel");
		confirmParams.m_msduHandle = m_txQueue.front ()->txQMsduHandle;
		confirmParams.m_status = IEEE_802_15_4_CHANNEL_ACCESS_FAILURE;
		m_macTxDropTrace (m_txPkt);
		// remove the copy of the packet that was just sent
		TxQueueElement *txQElement = m_txQueue.front ();
		txQElement->txQPkt = 0;
		delete txQElement;
		m_txQueue.pop_front ();
		switch (m_userCase)
		{
		case Mlme_Associate_Request:
		{
			//i'm not sending back the real value, just the state value is relevant
			if(!m_mlmeAssociateConfirmCallback.IsNull())
			{
				resetUserCase();
				m_MlmeAssociateConfirmParams.AssocShortAddress = Mac16Address();
				m_MlmeAssociateConfirmParams.SecurityLevel = 0;
				m_MlmeAssociateConfirmParams.status = IEEE_802_15_4_CHANNEL_ACCESS_FAILURE;
				m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);

			}
			else{
				NS_LOG_ERROR("m_mlmeAssociateConfirmCallback is not initialized");
			}
			break;
		}
		case Mlme_Poll_Request:
		{
			if(!m_mlmePollConfirmCallback.IsNull())
			{
				resetUserCase();
				MlmePollConfirmParams returnParams;
				returnParams.status = IEEE_802_15_4_CHANNEL_ACCESS_FAILURE;
				m_mlmePollConfirmCallback(returnParams);
			}
			else
			{
				NS_LOG_ERROR("m_mlmePollConfirmCallback is not initialized");
			}
			break;
		}
		case Mlme_Orphan_Response:
		case Mlme_Associate_Response:
		{
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
			{
				resetUserCase();
				m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_CHANNEL_ACCESS_FAILURE;
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			}
			else{
				NS_LOG_ERROR("m_mlmeCommStatusIndicationCallback is not initialized");
			}
			break;
		}
		case Mlme_Disassociate_Request:
		{
			if(!m_mlmeDisassociateConfirmCallback.IsNull())
			{
				//i'm not sending back the real value, just the state value is relevant
				resetUserCase();
				MlmeDisassociateConfirmParams returnParams;
				returnParams.status = IEEE_802_15_4_CHANNEL_ACCESS_FAILURE;
				m_mlmeDisassociateConfirmCallback(returnParams);
				break;
			}
			else
			{
				NS_LOG_ERROR("m_mlmeDisassociateConfirmCallback is not initialized");
			}
			break;
		}
		default:
		{
			if (!m_mcpsDataConfirmCallback.IsNull ())
			{
				m_mcpsDataConfirmCallback (confirmParams);
			}
			else
				NS_LOG_ERROR("m_mcpsDataConfirmCallback not initialized");

			break;
		}
		}
	}
	// if there are more packets waiting to be sent
	else if (!m_txQueue.empty ())
	{
		// Start CCA process for next packet in the tx queue
		m_txPkt = m_txQueue.front ()->txQPkt->Copy ();
		Ptr<Packet>tmPkt = m_txPkt->Copy();
		LrWpanMacHeader tmp;
		tmPkt->RemoveHeader(tmp);
		//ACK packet should be set without using the CSMA
		if(tmp.IsAcknowledgment())
		{
			double a = (double)(LrWpanPhy::aTurnaroundTime);
			double b = (double)(m_phy->GetDataOrSymbolRate(false));
			Time time2wait = Seconds(a / b);
			Simulator::Schedule(time2wait,&LrWpanMac::SetLrWpanMacState,this,CHANNEL_IDLE);
		}
		else
		{
			// Start CCA process for this packet
			Simulator::ScheduleNow (&LrWpanCsmaCa::Start, m_csmaCa);
		}
		tmPkt = 0;
	}
}



user_case
LrWpanMac::GetUserCase (void) const
{
	return m_userCase;
}

void
LrWpanMac::resetUserCase(void)
{
	NS_LOG_FUNCTION(this << m_userCase);
	switch (m_userCase)
	{
	case Mlme_Associate_Request:
	{
		m_CmdReceived =  false;
		m_ACK_received = false;
		m_numCmdRetry = 0;
		break;
	}
	case Mlme_Associate_Response:
	{
		m_ACK_received =  false;
		break;
	}
	case Mlme_Disassociate_Request:
	{
		m_ACK_received =  false;
		break;
	}
	case Mlme_Poll_Request:
	{
		m_CmdReceived =  false;
		m_ACK_received = false;
		m_numCmdRetry = 0;
		m_DataReceived = false;
		break;
	}
	case Mlme_RX_Enable_Request:
	{
		break;
	}
	case Mlme_Set_Request:
	{
		break;
	}
	case Mlme_Scan_Request:
	{
		m_CmdReceived = false;
		break;
	}
	case Mlme_No_Case:
	{
		m_CmdReceived =  false;
		m_ACK_received = false;
		m_numCmdRetry = 0;
		m_DataReceived = false;
		break;
	}
	case Mlme_Orphan_Response:
	{
		m_ACK_received = false;
		break;
	}
	default:
		break;
	}
	m_userCase = Mlme_No_Case;
	m_step = 0;
}
void
LrWpanMac::ChangeMacState (LrWpanMacState newState)
{
	NS_LOG_LOGIC (this << " change lrwpan mac state from "
			<< m_lrWpanMacState << " to "
			<< newState);
	m_macStateLogger (Simulator::Now (), m_lrWpanMacState, newState);
	m_lrWpanMacState = newState;
}
/*
 *********************************MLME MODULE*********************************
 */
void
LrWpanMac::MlmeSetRequest(MlmeSetRequestParams params)
{
	NS_LOG_FUNCTION(this);
	m_userCase = Mlme_Set_Request;
	LrWpanMACResultStatus status = IEEE_802_15_4_SUCCESS;
	if(params.isMACattribute)			//we control which type of PIB attribute we have to set
	{
		switch (params.PIBattributeID.mac_attributeID)
		{
		case macAckWaitDuration:
		case macMinLIFSPeriod:
		case macSyncSymbolOffset:
		case macMinSIFSPeriod:
		case macBeaconTxTime:
		case macSuperframeOrder:
			status=IEEE_802_15_4_READ_ONLY;
			break;
		case macAssociatedPANCoord:
			if(params.PIBattribute.mac_attribute->macAssociatedPANCoord==true)
			{
				NS_ASSERT_MSG((m_macPIBattributes.macShortAddress!=Mac16Address("00:00"))&&
						(m_macPIBattributes.macShortAddress!=Mac16Address("ff:ff")),
						"The macShortaddress is  not set as a legal value, this device does not seem to be associated");
			}
			m_macPIBattributes.macAssociatedPANCoord=params.PIBattribute.mac_attribute->macAssociatedPANCoord;
			break;
		case macAssociationPermit:
			if((params.PIBattribute.mac_attribute->macAssociationPermit==false)&&(m_macPIBattributes.macAssociatedPANCoord==true))
			{
				NS_LOG_INFO("I have already been associated with a coordinator!!");
			}
			m_macPIBattributes.macAssociationPermit=params.PIBattribute.mac_attribute->macAssociationPermit;
			break;
		case macAutoRequest:
			m_macPIBattributes.macAutoRequest=params.PIBattribute.mac_attribute->macAutoRequest;
			break;
			//todo:  see 7.5.1.4 for an explanation of how this attribute affects the backoff exponent in the CSMA-C algorithm
		case macBattLifeExt:
			m_macPIBattributes.macBattLifeExt=params.PIBattribute.mac_attribute->macBattLifeExt;
			break;
		case macBattLifeExtPeriods:
			if((params.PIBattribute.mac_attribute->macBattLifeExtPeriods<6)||
					params.PIBattribute.mac_attribute->macBattLifeExtPeriods>41)
			{
				status=IEEE_802_15_4_INVALID_PARAMETER;
			}
			else
			{
				m_macPIBattributes.macBattLifeExtPeriods=params.PIBattribute.mac_attribute->macBattLifeExtPeriods;
			}
			break;
		case macBeaconPayloadLength:					//macBeaconPayloadLength should be set first
			if(params.PIBattribute.mac_attribute->macBeaconPayloadLength>m_aMaxBeaconPayloadLength)
				status=IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macBeaconPayloadLength=params.PIBattribute.mac_attribute->macBeaconPayloadLength;
			break;
		case macBeaconPayload:
			if(params.PIBattribute.mac_attribute->macBeaconPayload.size()>m_macPIBattributes.macBeaconPayloadLength)
				status=IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macBeaconPayload=params.PIBattribute.mac_attribute->macBeaconPayload;
			break;
		case macBeaconOrder:
			if(params.PIBattribute.mac_attribute->macBeaconOrder>15)
				status=IEEE_802_15_4_INVALID_PARAMETER;
			else
				if(m_macPIBattributes.macBeaconOrder == 5){
					m_macPIBattributes.macRxOnWhenIdle=true;
				}
			m_macPIBattributes.macBeaconOrder = params.PIBattribute.mac_attribute->macBeaconOrder;
			break;
		case macBSN:
			m_macPIBattributes.macBSN = params.PIBattribute.mac_attribute->macBSN;
			break;
		case macCoordExtendedAddress:
			m_macPIBattributes.macCoordExtendedAddress = params.PIBattribute.mac_attribute->macCoordExtendedAddress;
			break;
		case macCoordShortAddress:
			m_macPIBattributes.macCoordShortAddress = params.PIBattribute.mac_attribute->macCoordShortAddress;
			break;
		case macDSN:
			m_macPIBattributes.macDSN = params.PIBattribute.mac_attribute->macDSN;
			break;
		case macGTSPermit:
			m_macPIBattributes.macGTSPermit = params.PIBattribute.mac_attribute->macGTSPermit;
			break;
		case macMaxBE:
			if((params.PIBattribute.mac_attribute->macMaxBE < 3)||(params.PIBattribute.mac_attribute->macMaxBE>8))
				status=IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macMaxBE = params.PIBattribute.mac_attribute->macMaxBE;
			break;
		case macMaxCSMABackoffs:
			if(params.PIBattribute.mac_attribute->macMaxCSMABackoffs > 5)
				status = IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macMaxCSMABackoffs = params.PIBattribute.mac_attribute->macMaxCSMABackoffs;
			break;
		case macMaxFrameTotalWaitTime:
			m_macPIBattributes.macMaxFrameTotalWaitTime = params.PIBattribute.mac_attribute->macMaxFrameTotalWaitTime;
			break;
		case macMaxFrameRetries:
			if(params.PIBattribute.mac_attribute->macMaxFrameRetries > 7)
				status = IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macMaxFrameRetries = params.PIBattribute.mac_attribute->macMaxFrameRetries;
			break;
		case macMinBE:
			if(params.PIBattribute.mac_attribute->macMinBE > m_macPIBattributes.macMaxBE)
				status=IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macMinBE = params.PIBattribute.mac_attribute->macMinBE;
			break;
			//we are using the value "0" for the macPANID for transmission with PANID compression
		case macPANId:
			if((params.PIBattribute.mac_attribute->macPANId > 0xffff)||(params.PIBattribute.mac_attribute->macPANId == 0))
				status = IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macPANId = params.PIBattribute.mac_attribute->macPANId;
			break;
			//7.5.6.5 of 802.15.4-2006
		case macPromiscuousMode:
			if(params.PIBattribute.mac_attribute->macPromiscuousMode)
				PlmeSetTRXStateConfirm(IEEE_802_15_4_PHY_RX_ON);
			else{
				if(m_macPIBattributes.macRxOnWhenIdle)
					PlmeSetTRXStateConfirm(IEEE_802_15_4_PHY_RX_ON);
				else
				{
					PlmeSetTRXStateConfirm(IEEE_802_15_4_PHY_TRX_OFF);
				}
			}
			m_macPIBattributes.macPromiscuousMode = params.PIBattribute.mac_attribute->macPromiscuousMode;
			break;
		case macResponseWaitTime:
			if((params.PIBattribute.mac_attribute->macResponseWaitTime < 2)||(params.PIBattribute.mac_attribute->macResponseWaitTime > 64))
				status = IEEE_802_15_4_INVALID_PARAMETER;
			else
				m_macPIBattributes.macResponseWaitTime = params.PIBattribute.mac_attribute->macPromiscuousMode;
			break;
		case macRxOnWhenIdle:
			m_macPIBattributes.macRxOnWhenIdle = params.PIBattribute.mac_attribute->macRxOnWhenIdle;
			break;
		case macSecurityEnabled:
			m_macPIBattributes.macSecurityEnabled = params.PIBattribute.mac_attribute->macSecurityEnabled;
			break;
		case macShortAddress:
			NS_ASSERT_MSG(params.PIBattribute.mac_attribute->macShortAddress != Mac16Address("00:00"),"this adress (00:00) is invalid");
			m_macPIBattributes.macShortAddress = params.PIBattribute.mac_attribute->macShortAddress;
			break;
		case macTransactionPersistenceTime:
			m_macPIBattributes.macTransactionPersistenceTime = params.PIBattribute.mac_attribute->macTransactionPersistenceTime;
			break;
		default:
			status = IEEE_802_15_4_UNSUPPORTED_ATTRIBUTE;
			break;
		}
		m_mlmeSetConfirmParams.status = status;
		m_mlmeSetConfirmParams.PIBattributeID.mac_attributeID = params.PIBattributeID.mac_attributeID;
		m_mlmeSetConfirmParams.isMACattribute = true;
		resetUserCase();
		if(!m_mlmeSetConfirmCallback.IsNull())
			m_mlmeSetConfirmCallback(m_mlmeSetConfirmParams);
		else
			NS_LOG_ERROR("m_mlmeSetConfirmCallback not initialized");
	}
	else{
		m_phy->PlmeSetAttributeRequest(params.PIBattributeID.phy_attributeID,params.PIBattribute.phy_attribute);
		if(PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_INVALID_PARAMETER)
			status=IEEE_802_15_4_INVALID_PARAMETER;
		else if(PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE)
			status=IEEE_802_15_4_UNSUPPORTED_ATTRIBUTE;
		else if(PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_READ_ONLY)
			status=IEEE_802_15_4_READ_ONLY;
		resetUserCase();
		m_mlmeSetConfirmParams.status = status;
		m_mlmeSetConfirmParams.isMACattribute = false;
		m_mlmeSetConfirmParams.PIBattributeID.phy_attributeID = params.PIBattributeID.phy_attributeID;


		if(!m_mlmeSetConfirmCallback.IsNull())
			m_mlmeSetConfirmCallback(m_mlmeSetConfirmParams);
		else
			NS_LOG_ERROR("m_mlmeSetConfirmCallback not initialized");
	}
}

void
LrWpanMac::MlmeOrphanResponse(MlmeOrphanResponseParams params)
{
	NS_LOG_FUNCTION(this);
	if(params.SecurityLevel > 0)
	{
		//todo implement security for the frame
	}
	MlmeCommStatusIndicationParams retParams;
	retParams.DstAddr = params.OrphanAddress.operator ns3::Address();
	retParams.DstAddrMode = EXT_ADDR;
	retParams.PANId = m_macPIBattributes.macPANId;
	retParams.SecurityLevel = params.SecurityLevel;
	retParams.SrcAddr = m_selfExt;
	retParams.SrcAddrMode = EXT_ADDR;
	switch (m_step)
	{
	case 0:
	{
		//we check the input parameters
		if(params.ShortAddress == Mac16Address("ff:ff"))
		{
			NS_LOG_ERROR(this << "short address not valid");
			retParams.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(retParams);
			else
				NS_LOG_ERROR("m_mlmeCommStatusIndicationCallback is not initialized");

		}
		if(params.AssociatedMember == true)
		{
			m_MlmeOrphanResponseParams.OrphanAddress = params.OrphanAddress;
			m_MlmeOrphanResponseParams.ShortAddress = params.ShortAddress;
			m_MlmeOrphanResponseParams.AssociatedMember = params.AssociatedMember;
			m_MlmeOrphanResponseParams.SecurityLevel = params.SecurityLevel;
			m_step++;
			m_userCase = Mlme_Orphan_Response;
			//we construct a realignment command
			LrWpanMacHeader OrphHdr;
			uint8_t payload[9];
			payload[0] = 0x08;				//0x08 represents the coordinator realignment
			//we add the pan id in the payload array of the packet
			payload[1] = ((m_macPIBattributes.macPANId) & (0x00FF));
			payload[2] = ((m_macPIBattributes.macPANId) >> 8);
			//we add the orphan the coordinator short address in the packet payload
			uint8_t addressPayload[2];
			m_macPIBattributes.macShortAddress.CopyTo(addressPayload);
			payload[3] = addressPayload[0];
			payload[4] = addressPayload[1];
			m_phy->PlmeGetAttributeRequest(phyCurrentChannel);
			payload[5] = m_tmpPhyPIBattributes.phyCurrentChannel;
			//we add the device short address to the packet payload
			params.ShortAddress.CopyTo(addressPayload);
			payload[6] = addressPayload[0];
			payload[7] = addressPayload[1];
			payload[8] = m_tmpPhyPIBattributes.phyCurrentPage;
			Ptr < Packet > Pkt = Create<Packet>(payload,sizeof(payload));
			MlmeconstructCommandHeader(Pkt, &OrphHdr, EXT_ADDR, 0xffff, params.OrphanAddress, EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt,params.SecurityLevel, false, true);
			addToPktBuffer (Pkt, 0);
		}
		else
		{
			//shouldn't happen
			NS_LOG_ERROR(this << "the associatedMember params of the associateResponse is not well setted");
		}
		break;
	}
	case 1:
	{
		m_step ++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time Wait4ACK = Seconds(a / b);
		m_ACK_received = false;
		m_ACKEvent = Simulator::Schedule(Wait4ACK, &LrWpanMac::MlmeOrphanResponse,this,m_MlmeOrphanResponseParams);
		break;
	}
	case 2:
	{

		if(!m_ACK_received)
		{

			retParams.status = IEEE_802_15_4_NO_ACK;
			resetUserCase();
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(retParams);
			else
				NS_LOG_ERROR("m_mlmeCommStatusIndicationCallback is not initialized");
		}
		else
		{
			m_ACKEvent.Cancel();
			resetUserCase();
			retParams.status = IEEE_802_15_4_SUCCESS;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(retParams);
			else
				NS_LOG_ERROR("m_mlmeCommStatusIndicationCallback is not initialized");
		}
		break;
	}
	default:
		break;
	}
}

void
LrWpanMac::MlmeGetRequest(MlmeGetRequestParams params)
{
	NS_LOG_FUNCTION(this);
	m_userCase = Mlme_Get_Request;
	LrWpanMACResultStatus status = IEEE_802_15_4_SUCCESS;
	if(params.isMACattribute)
	{
		switch (params.PIBattributeID.mac_attributeID)
		{
		case    macAckWaitDuration:
		case	macAssociatedPANCoord:
		case 	macAssociationPermit:
		case 	macAutoRequest:
		case 	macBattLifeExt:
		case 	macBattLifeExtPeriods:
		case 	macBeaconPayload:
		case 	macBeaconPayloadLength:
		case 	macBeaconOrder:
		case 	macBeaconTxTime:
		case 	macBSN:
		case 	macCoordExtendedAddress:
		case 	macCoordShortAddress:
		case 	macDSN:
		case 	macGTSPermit:
		case 	macMaxBE:
		case 	macMaxCSMABackoffs:
		case 	macMaxFrameTotalWaitTime:
		case 	macMaxFrameRetries:
		case 	macMinBE:
		case 	macPANId:
		case 	macMinLIFSPeriod:
		case 	macMinSIFSPeriod:
		case 	macPromiscuousMode:
		case 	macResponseWaitTime:
		case 	macRxOnWhenIdle:
		case 	macSecurityEnabled:
		case 	macShortAddress:
		case 	macSuperframeOrder:
		case 	macSyncSymbolOffset:
		case 	macTransactionPersistenceTime:

			break;
		default:
			status=IEEE_802_15_4_UNSUPPORTED_ATTRIBUTE;
			break;
		}
		m_MlmeGetConfirmParams.isMACattribute = true;
		m_MlmeGetConfirmParams.PIBattribute.mac_attribute=&m_macPIBattributes;
		m_MlmeGetConfirmParams.status = status;
		resetUserCase();
		if(!m_mlmeGetConfirmCallback.IsNull())
			m_mlmeGetConfirmCallback(m_MlmeGetConfirmParams);
		else
			NS_LOG_ERROR("m_mlmeGetConfirmCallback not initialized");
	}
	else
	{
		m_phy->PlmeGetAttributeRequest(params.PIBattributeID.phy_attributeID);
		if(PlmeAttributeConfirmStatus==IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE)
			status=IEEE_802_15_4_UNSUPPORTED_ATTRIBUTE;
		m_MlmeGetConfirmParams.isMACattribute=false;
		m_MlmeGetConfirmParams.status=status;
		m_MlmeGetConfirmParams.PIBattribute.phy_attribute=&m_tmpPhyPIBattributes;
		resetUserCase();
		if(!m_mlmeGetConfirmCallback.IsNull())
			m_mlmeGetConfirmCallback(m_MlmeGetConfirmParams);
		else
			NS_LOG_ERROR("m_mlmeGetConfirmCallback is not initialized");

	}
}

void
LrWpanMac::MlmeRXEnableRequest(MlmeRXEnableRequestParams params)
{
	NS_LOG_FUNCTION(this);
	switch (m_step)
	{
	case 0:
	{
		m_userCase = Mlme_RX_Enable_Request;
		m_MlmeRXEnableRequestParams = params;
		//We check the params
		if(params.RxOnDuration > 0xffffff || params.RxOnTime > 0xffffff)
		{
			resetUserCase();
			m_MlmeRXEnableConfirmParams.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmeRXEnableConfirmCallback.IsNull())
				m_mlmeRXEnableConfirmCallback(m_MlmeRXEnableConfirmParams);
			else
				NS_LOG_ERROR("m_mlmeRXEnableConfirmCallback not initialized");
			return;
		}
		//as beacon are not yet included
		//parameters deferpermit and RxOnTime are ignored
		if(params.RxOnDuration == 0)					//we must disable the transmitter
		{
			resetUserCase();
			m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
			m_MlmeRXEnableConfirmParams.status = IEEE_802_15_4_SUCCESS;
			if(!m_mlmeRXEnableConfirmCallback.IsNull())
				m_mlmeRXEnableConfirmCallback(m_MlmeRXEnableConfirmParams);
			else
				NS_LOG_ERROR("m_mlmeRXEnableConfirmCallback not initialized");
			return;
		}
		else
		{
			m_step++;
			m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
			MlmeRXEnableRequest(m_MlmeRXEnableRequestParams);
		}
		break;
	}
	case 1:
	{
		if(PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_RX_ON || PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_SUCCESS)
		{
			//we successfully set the transmitter on
			Time timeToWait = Seconds(params.RxOnDuration/m_phy->GetDataOrSymbolRate(false));
			Simulator::Schedule(timeToWait,&LrWpanPhy::PlmeSetTRXStateRequest,m_phy,IEEE_802_15_4_PHY_TRX_OFF);
			m_MlmeRXEnableConfirmParams.status = IEEE_802_15_4_SUCCESS;
			resetUserCase();
			if(!m_mlmeRXEnableConfirmCallback.IsNull())
				m_mlmeRXEnableConfirmCallback(m_MlmeRXEnableConfirmParams);
			else
				NS_LOG_ERROR("m_mlmeRXEnableConfirmCallback not initialized");
		}
		else
		{
			//todo if TX_Active
		}
		break;
	}
	default:
		break;
	}
}

void
LrWpanMac::ResetMacPIBattributes()
{
	LrwpanMacPIBattributes def_MacAttribute;
	def_MacAttribute.macAckWaitDuration = 54;  // equation 13 : macAckWaitDuration =	aUnitBackoffPeriod + aTurnaroundTime
	//	+ phySHRDuration + 6 ⋅ phySymbolsPerOctet
	def_MacAttribute.macAssociatedPANCoord = false;
	def_MacAttribute.macAssociationPermit = false;
	def_MacAttribute.macAutoRequest = true;
	SeedManager::SetSeed (100);
	UniformVariable uniformVar;
	uniformVar = UniformVariable (0, 255);
	def_MacAttribute.macBSN = SequenceNumber16 (uniformVar.GetValue ());
	def_MacAttribute.macBattLifeExt = false;
	def_MacAttribute.macBattLifeExtPeriods = 0; //todo calculate this param
	def_MacAttribute.macBeaconOrder = 15;
	//	  def_defMacAttribute.macBeaconPayload
	def_MacAttribute.macBeaconPayloadLength = 0;
	def_MacAttribute.macBeaconTxTime = 0;
	//	  def_MacAttribute.macCoordExtendedAddress
	def_MacAttribute.macCoordShortAddress = Mac16Address("ff:ff");
	def_MacAttribute.macDSN = SequenceNumber16(uniformVar.GetValue());
	def_MacAttribute.macGTSPermit = true;
	def_MacAttribute.macMaxBE = 5;
	def_MacAttribute.macMaxCSMABackoffs = 4;
	def_MacAttribute.macMaxFrameRetries = 3;
	def_MacAttribute.macMaxFrameTotalWaitTime = 2622;			//see equation 14
	def_MacAttribute.macMinBE = 3;
	def_MacAttribute.macMinLIFSPeriod = 40;
	def_MacAttribute.macMinSIFSPeriod = 12;
	def_MacAttribute.macPANId = 0;
	def_MacAttribute.macPromiscuousMode = false;
	def_MacAttribute.macResponseWaitTime = 32;
	def_MacAttribute.macRxOnWhenIdle = true;
	def_MacAttribute.macSecurityEnabled = false;
	def_MacAttribute.macShortAddress = Mac16Address("ff:ff");
	def_MacAttribute.macSuperframeOrder = 15;
	// def_MacAttribute.macSyncSymbolOffset = implementation specific
	// def_MacAttribute.macTimestampSupported = implementation specific
	def_MacAttribute.macTransactionPersistenceTime = 0x01f4;

	def_MacPIBattributes  = def_MacAttribute;
}
uint8_t
LrWpanMac::createCapabilityInformation(bool alternatePANCoordinator,bool deviceTypeIsFFD,bool powerSourceIsMain,bool ReceiverOnWhenIdle,bool SecurityCapability,bool AllocateAddress)
{
	uint8_t capabilityInformation=0x00;
	if(alternatePANCoordinator)
		capabilityInformation = capabilityInformation | (0x01<<7);
	if(deviceTypeIsFFD)
		capabilityInformation = capabilityInformation|(0x01<<6);
	if(powerSourceIsMain)
		capabilityInformation = capabilityInformation|(0x01<<5);
	if(ReceiverOnWhenIdle)
		capabilityInformation = capabilityInformation|(0x01<<4);
	if(SecurityCapability)
		capabilityInformation = capabilityInformation|(0x01<<1);
	if(AllocateAddress)
		capabilityInformation = capabilityInformation|(0x01);
	return capabilityInformation;
}

void
LrWpanMac::MlmeAssociateRequest(MlmeAssociateRequestParams params)
{
	NS_LOG_FUNCTION(this << Mac16Address::ConvertFrom(params.CoordAddress) );
	if(params.SecurityLevel > 0)
	{
		//todo implement security for the frame
	}
	switch (m_step) {
	case 0:
	{
		m_userCase = Mlme_Associate_Request;
		m_step++;
		//we saved the input value for further use in case of failure
		m_MlmeAssociateRequestParams.CapabilityInformation = params.CapabilityInformation;
		m_MlmeAssociateRequestParams.CoordAddrMode = params.CoordAddrMode;
		m_MlmeAssociateRequestParams.CoordAddress = params.CoordAddress;
		m_MlmeAssociateRequestParams.CoordPANId = params.CoordPANId;
		m_MlmeAssociateRequestParams.SecurityLevel = params.SecurityLevel;
		m_MlmeAssociateRequestParams.LogicalChannel = params.LogicalChannel;
		if(((params.CoordAddrMode != SHORT_ADDR) && (params.CoordAddrMode  != EXT_ADDR))||
				(!m_phy->ChannelSupported(params.LogicalChannel)))
		{

			m_MlmeAssociateConfirmParams.AssocShortAddress = Mac16Address();
			m_MlmeAssociateConfirmParams.SecurityLevel = params.SecurityLevel;
			m_MlmeAssociateConfirmParams.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmeAssociateConfirmCallback.IsNull())
				m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
			else
				NS_LOG_ERROR("m_mlmeAssociateConfirmCallback is not initialized");
			return;
		}
		m_tmpPhyPIBattributes.phyCurrentChannel = params.LogicalChannel;
		m_phy->PlmeSetAttributeRequest(phyCurrentChannel, &m_tmpPhyPIBattributes);
		m_macPIBattributes.macPANId = params.CoordPANId;
		if(params.CoordAddrMode == EXT_ADDR)

			m_macPIBattributes.macCoordExtendedAddress = Mac64Address::ConvertFrom(params.CoordAddress);
		else{
			NS_ASSERT_MSG(Mac16Address::ConvertFrom(params.CoordAddress) != Mac16Address("ff:fe"),"the short address is illegal,Ext address should be used instead");
			m_macPIBattributes.macCoordShortAddress = Mac16Address::ConvertFrom(params.CoordAddress);
		}
		//we do create the associate command header
		LrWpanMacHeader cmdHdr;
		uint8_t payload[2];
		payload[0] = 0x01;			//0x01 represent the command type
		payload[1] = params.CapabilityInformation;
		NS_LOG_DEBUG("the size of the packet buffer is " << sizeof(payload));
		Ptr < Packet > pkt = Create<Packet>(payload,2);
		MlmeconstructCommandHeader(pkt,&cmdHdr,params.CoordAddrMode,params.CoordPANId,params.CoordAddress,EXT_ADDR,0xffff,
				m_selfExt.operator ns3::Address(),params.SecurityLevel,false,true);
		addToPktBuffer(pkt,0);// we set the msduHandle to zero
		break;
	}
	case 1:
	{
		NS_LOG_DEBUG("Association command request transmitted");
		m_step++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time time4ACK = Seconds(a / b);
		m_ACK_received = false;
		NS_LOG_DEBUG(time4ACK.GetMicroSeconds());
		m_ACKEvent = Simulator::Schedule(time4ACK, &LrWpanMac::MlmeAssociateRequest, this, m_MlmeAssociateRequestParams);
		break;
	}
	case 2:
	{
		if(!m_ACK_received)//ack failed
		{
			m_step = 0;
			if(m_numCmdRetry <= m_macPIBattributes.macMaxFrameRetries)
			{
				NS_LOG_DEBUG("ACK not received, we retransmit");
				m_numCmdRetry++;
				MlmeAssociateRequest(params);
			}else
			{
				NS_LOG_DEBUG("ACK not received, can't transmit anymore");
				m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
				if(params.CoordAddrMode == EXT_ADDR)
					m_macPIBattributes.macCoordExtendedAddress = def_MacPIBattributes.macCoordExtendedAddress;
				else{
					m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
				}
				m_MlmeAssociateConfirmParams.SecurityLevel = params.SecurityLevel;
				m_MlmeAssociateConfirmParams.AssocShortAddress = Mac16Address();
				m_MlmeAssociateConfirmParams.status = IEEE_802_15_4_NO_ACK;
				resetUserCase();
				if(!m_mlmeAssociateConfirmCallback.IsNull())
					m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
				else
					NS_LOG_ERROR("m_mlmeAssociateConfirmCallback is not initialized");
				return;
			}
			break;
		}
		else
		{
			NS_ASSERT(m_ACK_received);//ack received
			NS_LOG_DEBUG("ACK received");
			//i cancel the event relatives to the ACK wait
			m_ACKEvent.Cancel();
			m_step++;
			m_numCmdRetry = 0;
			double a = (double)(m_macPIBattributes.macResponseWaitTime);
			double b = (double)(m_phy->GetDataOrSymbolRate(false));
			Time wait = Seconds(a / b);
			Simulator::Schedule(wait,&LrWpanMac::MlmeAssociateRequest,this,m_MlmeAssociateRequestParams);
			break;
		}
	}
	case 3:
	{
		NS_LOG_DEBUG("we send  a data request to extract the response");
		m_step++;
		LrWpanMacHeader CmddataHdr;
		uint8_t payload;
		//0x04 represents the MAC data request command
		payload = 0x04;
		Ptr < Packet > pkt = Create<Packet>(&payload,1);
		MlmeconstructCommandHeader(pkt, &CmddataHdr, params.CoordAddrMode, m_macPIBattributes.macPANId, params.CoordAddress,
				EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt, params.SecurityLevel,false, true);
		addToPktBuffer (pkt,0);
		break;
	}
	case 4:
	{
		//we transmitted the datarequest command and now we are waitin for the ACK
		NS_LOG_DEBUG("Data request transmitted");
		m_step++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time wait4ACK = Seconds(a / b);
		m_ACK_received = false;
		m_CmdReceived = false;
		m_ACKEvent = Simulator::Schedule(wait4ACK, &LrWpanMac::MlmeAssociateRequest, this, m_MlmeAssociateRequestParams);
		break;
	}
	case 5: // we are waitin for the ack
	{
		if(!m_ACK_received)//time out waitin ack
		{
			if(m_numCmdRetry <= m_macPIBattributes.macMaxFrameRetries)
			{
				NS_LOG_DEBUG("we didn't receive the ack, we retransmit");
				m_step = 3;
				m_numCmdRetry++;
				MlmeAssociateRequest(m_MlmeAssociateRequestParams);
			}else{
				NS_LOG_DEBUG("we didn't receive the data request command  ack, and we can't transmit anymore:return no ack");
				m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
				if(params.CoordAddrMode == EXT_ADDR)
					m_macPIBattributes.macCoordExtendedAddress = def_MacPIBattributes.macCoordExtendedAddress;
				else{
					m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
				}
				m_MlmeAssociateConfirmParams.AssocShortAddress = Mac16Address();
				m_MlmeAssociateConfirmParams.SecurityLevel = params.SecurityLevel;
				m_MlmeAssociateConfirmParams.status = IEEE_802_15_4_NO_ACK;
				resetUserCase();
				if(!m_mlmeAssociateConfirmCallback.IsNull())
					m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
				else
					NS_LOG_ERROR("m_MlmeAssociateConfirmParams not initialized");
				return;
			}
		}
		else{
			NS_ASSERT(m_ACK_received);//ack received
			NS_LOG_DEBUG("ACK received, waiting for the association response");
			//we cancel the ackEvent/todo reset usercase
			m_ACKEvent.Cancel();
			m_step++;
			m_ACK_received = false;
			m_numCmdRetry = 0;
			double a=(double)m_macPIBattributes.macMaxFrameTotalWaitTime;
			double b=(double)m_phy->GetDataOrSymbolRate(false);
			Time wait4Data=Seconds(a / b);
			m_DataEvent = Simulator::Schedule(wait4Data,&LrWpanMac::MlmeAssociateRequest,this,m_MlmeAssociateRequestParams);
		}
		break;
	}
	case 6: // wait for the data
	{
		if(m_CmdReceived == false)
		{
			NS_LOG_DEBUG("no data received,return no data");
			m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
			if(params.CoordAddrMode == EXT_ADDR)
				m_macPIBattributes.macCoordExtendedAddress = def_MacPIBattributes.macCoordExtendedAddress;
			else{
				m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
			}
			resetUserCase();
			m_MlmeAssociateConfirmParams.AssocShortAddress = Mac16Address();
			m_MlmeAssociateConfirmParams.SecurityLevel = params.SecurityLevel;
			m_MlmeAssociateConfirmParams.status = IEEE_802_15_4_NO_DATA;
			if(!m_mlmeAssociateConfirmCallback.IsNull())
				m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
			else
				NS_LOG_ERROR("m_mlmeAssociateConfirmCallback not initialized");
			return;
		}else
		{
			NS_LOG_DEBUG("node" << m_selfExt <<" received the data");
			m_DataEvent.Cancel();
			resetUserCase();
			if(!m_mlmeAssociateConfirmCallback.IsNull())
			{
				if((m_MlmeAssociateConfirmParams.status == IEEE_802_15_4_PAN_ACCESS_DENIED) ||
						(m_MlmeAssociateConfirmParams.status == IEEE_802_15_4_PAN_AT_CAPACITY))
				{
					m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
					if(params.CoordAddrMode == EXT_ADDR)
						m_macPIBattributes.macCoordExtendedAddress = def_MacPIBattributes.macCoordExtendedAddress;
					else{
						m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
					}
					m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
					return;
				}
				else
				{
					NS_ASSERT(m_MlmeAssociateConfirmParams.status == IEEE_802_15_4_ASSOCIATION_SUCCESSFULL);
					m_macPIBattributes.macAssociatedPANCoord = true;
					m_macPIBattributes.macShortAddress = m_MlmeAssociateConfirmParams.AssocShortAddress;
					//todo find a way to set both the coordAddresses
					m_mlmeAssociateConfirmCallback(m_MlmeAssociateConfirmParams);
					return;
				}
			}else
			{
				NS_LOG_ERROR("m_mlmeAssociateConfirmCallback is not initialized");
			}
		}
		break;
	}
	default:
		break;
	}
}
void
LrWpanMac::MlmeDisassociateRequest(MlmeDisassociateRequestParams params)
{
	NS_LOG_FUNCTION(this);
	m_MlmeDisassociateRequestParams.DeviceAddrMode = params.DeviceAddrMode;
	m_MlmeDisassociateRequestParams.TxIndirect = params.TxIndirect;
	m_MlmeDisassociateRequestParams.SecurityLevel = params.SecurityLevel;
	m_MlmeDisassociateRequestParams.DevicePANId = params.DevicePANId;
	m_MlmeDisassociateRequestParams.DisassociateReason = params.DisassociateReason;
	m_MlmeDisassociateRequestParams.DeviceAddress = params.DeviceAddress;
	switch (m_step)
	{
	case 0:
	{
		if(params.DevicePANId != m_macPIBattributes.macPANId)
		{

			m_step = 1;
			NS_LOG_ERROR("the PanId is not corresponding");
			MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
			return;

		}
		if(params.DisassociateReason != 0x01 && params.DisassociateReason != 0x02)
		{
			m_step = 1;
			NS_LOG_ERROR("The disassociation Reason is not a valid one");
			MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
			return;
		}
		if(((params.DeviceAddrMode == SHORT_ADDR) && (params.DeviceAddress == m_macPIBattributes.macCoordShortAddress.operator ns3::Address()))
				|| ((params.DeviceAddrMode == EXT_ADDR) && (params.DeviceAddress == m_macPIBattributes.macCoordExtendedAddress.operator ns3::Address())))
		{
			//this device is not the coordinator so the TXindirect param is not needed
			if(params.DisassociateReason == 0x02)
			{
				if(params.DeviceAddrMode == SHORT_ADDR && Mac16Address::ConvertFrom(params.DeviceAddress) == Mac16Address("ff:fe"))
				{
					NS_ASSERT_MSG(m_macPIBattributes.macShortAddress == Mac16Address("ff:fe"),"address not corresponding");
					NS_LOG_ERROR("Received a MACAddress == ff:fe, MAC64Address address should be used instead");
					m_MlmeDisassociateRequestParams.DeviceAddrMode = EXT_ADDR;		//we will use the  extended address instead
					m_MlmeDisassociateRequestParams.DeviceAddress = m_selfExt.operator ns3::Address();
				}
				m_step = 4;
			}
			else			//disassociateReason =0x01 so i should be a coordinator
			{

				NS_LOG_ERROR("the device seems to be a RFD but the disassociate Reason is not corresponding");
				m_step = 1;
				MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
				return;
			}
		}
		else
		{
			if(((params.DeviceAddrMode == SHORT_ADDR) && (params.DeviceAddress != m_macPIBattributes.macCoordShortAddress)) ||
					((params.DeviceAddrMode == EXT_ADDR) && (params.DeviceAddress != m_macPIBattributes.macCoordExtendedAddress)))
			{
				//we verify that way that the primitive caller is the coordinator we could either use the disassociate reason for the same purpose
				if(m_macPIBattributes.macCoordExtendedAddress == m_selfExt)			//this device is the coordinator
				{
					if(params.DisassociateReason == 0x02)	//the disassociate reason should be 0x01 because it's the coordinator
					{

						NS_LOG_ERROR("the device seems to be a RFD but the disassociation Reason is not corresponding");
						m_step = 1;
						MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
						return;
					}
					else
					{
						//we check if the address we set as input are valid
						if(params.DeviceAddrMode == SHORT_ADDR && Mac16Address::ConvertFrom(params.DeviceAddress) == Mac16Address("ff:fe"))
						{
							//the coordinator don't know the device extended address so we end up here
							NS_LOG_ERROR("Received a MACAddress == ff:fe, MAC64Address address should be used instead");
							m_step = 1;
							MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
							return;
						}
						if(params.TxIndirect)			//we will use indirect transmission
							m_step = 2;
						else
							m_step = 4;
					}
				}
				else
				{

					NS_LOG_ERROR("the device doesn't seem to be the coordinator nor a RFD");
					m_step = 1;
					MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
					return;
				}
			}
			else
			{
				m_step = 1;
				MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
				return;
			}
		}
		if(params.SecurityLevel > 0)
		{
			//todo implement security for the frame
		}
		//we recall the function to proceed with all the non failure cases
		MlmeDisassociateRequest(m_MlmeDisassociateRequestParams);
		break;
	}
	case 1:
	{
		resetUserCase();
		MlmeDisassociateConfirmParams param;
		param.DeviceAddrMode = params.DeviceAddrMode;
		param.DeviceAddress = params.DeviceAddress;
		param.DevicePANId = params.DevicePANId;
		param.status = IEEE_802_15_4_INVALID_PARAMETER;
		if(!m_mlmeDisassociateConfirmCallback.IsNull())
			m_mlmeDisassociateConfirmCallback(param);
		else
			NS_LOG_ERROR(this << " m_mlmedisassociateConfirmCallback is not initialized");
		return;
	}
	case 2: 				//indirect transmission case TXindirect == true step 1
	{
		//we first check if there is still place in the transactionList
		m_userCase = Mlme_Disassociate_Request;
		m_step ++;
		NS_ASSERT_MSG(this->GetObject<LrWpanTransactionList>(),"transactionList not initialized");
		if(this->GetObject<LrWpanTransactionList>()->isfull())
		{
			//the list is full
			MlmeDisassociateConfirmParams param;
			param.DeviceAddrMode = params.DeviceAddrMode;
			param.DeviceAddress = params.DeviceAddress;
			param.DevicePANId = params.DevicePANId;
			param.status = IEEE_802_15_4_TRANSACTION_OVERFLOW;
			resetUserCase();
			if(!m_mlmeDisassociateConfirmCallback.IsNull())
				m_mlmeDisassociateConfirmCallback(param);
			else
				NS_LOG_ERROR("m_mlmeDisassociateConfirmCallback is not initialized");
			return;
		}
		//we construct the disassociation command header here
		LrWpanMacHeader DISCmdHdr;
		uint8_t payload[2];
		payload[0] = 0x03;			//0x03 represents the disassociation notification command
		payload[1] = (uint8_t)params.DisassociateReason;
		Ptr<Packet> pkt = Create<Packet>(payload,sizeof(payload));
		if(params.DisassociateReason == 0x01)	// this node is the coordinator
			MlmeconstructCommandHeader(pkt, &DISCmdHdr, params.DeviceAddrMode, params.DevicePANId, params.DeviceAddress,
					EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt, params.SecurityLevel,false,true);
		else			//this node is not the coordinator
			MlmeconstructCommandHeader(pkt, &DISCmdHdr, EXT_ADDR, params.DevicePANId, m_macPIBattributes.macCoordExtendedAddress,
					EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt, params.SecurityLevel,false,true);
		this->GetObject<LrWpanTransactionList>()->add(pkt);
		double a = (double)(m_macPIBattributes.macTransactionPersistenceTime);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time TransactionTime = Seconds(a / b);
		m_transactionEvent = Simulator::Schedule(TransactionTime,&LrWpanMac::MlmeDisassociateRequest,this, m_MlmeDisassociateRequestParams);
		NS_LOG_DEBUG("transactions setted");
		break;
	}
	case 3: //TX indirect == true  step 2
	{
		bool found;  //# of packet in the transaction list for the corresponding device

		found = this->GetObject<LrWpanTransactionList>()->search(m_MlmeDisassociateRequestParams.DeviceAddress,m_MlmeDisassociateRequestParams.DeviceAddrMode);
		if(found)
		{
			this->GetObject<LrWpanTransactionList>()->cancelTransaction();		//we cancel the transaction from the transactionList
			MlmeDisassociateConfirmParams param;
			param.DeviceAddrMode = params.DeviceAddrMode;
			param.DeviceAddress = params.DeviceAddress;
			param.DevicePANId = params.DevicePANId;
			param.status = IEEE_802_15_4_TRANSACTION_EXPIRED;
			//the coordinator consider the device disassociated so it should be removed from the associatedDeviceList
			NS_ASSERT_MSG(this->GetObject<LrWpanAssociatedDevice>(),"LrwpanAssociatedDevice not intialized");
			this->GetObject<LrWpanAssociatedDevice>()->removeAssociateDevice(m_MlmeDisassociateRequestParams.DeviceAddress,m_MlmeDisassociateRequestParams.DeviceAddrMode);
			resetUserCase();
			if(!m_mlmeDisassociateConfirmCallback.IsNull())
				m_mlmeDisassociateConfirmCallback(param);
			else
				NS_LOG_ERROR("the m_mlmeDisassociateConfirmCallback has not been initialized");
			return;
		}
		else		//packet not found ,it has already been sent, we wait the ACK
		{
			m_step = 6;				// we jump to the final case
			NS_LOG_DEBUG("the packet has been sent from the transaction list");
			double a = (double)(m_macPIBattributes.macAckWaitDuration);
			double b = (double)(m_phy->GetDataOrSymbolRate(false));
			Time Wait4ACK = Seconds(a / b);
			m_ACK_received = false;
			m_ACKEvent = Simulator::Schedule(Wait4ACK, &LrWpanMac::MlmeDisassociateRequest,this,m_MlmeDisassociateRequestParams);
			break;
		}
		break;
	}
	case 4:			//Tx indirect == false step 1
	{
		m_step ++;
		m_userCase = Mlme_Disassociate_Request;
		//we construct the disassociation command header here
		LrWpanMacHeader DISCmdHdr;
		uint8_t payload[2];
		payload[0] = 0x03;			//0x03 represents the disassociation notification command
		payload[1] = (uint8_t)params.DisassociateReason;
		Ptr<Packet> pkt = Create<Packet>(payload,sizeof(payload));
		if(params.DisassociateReason == 0x01)	// this node is the coordinator
			MlmeconstructCommandHeader(pkt, &DISCmdHdr, params.DeviceAddrMode, params.DevicePANId, params.DeviceAddress,
					EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt, params.SecurityLevel,false,true);
		else			//this node is not the coordinator
			MlmeconstructCommandHeader(pkt, &DISCmdHdr, EXT_ADDR, params.DevicePANId, m_macPIBattributes.macCoordExtendedAddress,
					EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt, params.SecurityLevel,false,true);
		addToPktBuffer(pkt,0);
		break;
	}
	case 5:			//Tx indirect == false step 2
	{
		m_step ++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time Wait4ACK = Seconds(a / b);
		m_ACK_received = false;
		m_ACKEvent = Simulator::Schedule(Wait4ACK, &LrWpanMac::MlmeDisassociateRequest,this,m_MlmeDisassociateRequestParams);
		break;
	}
	case 6:			//both TX indirect step 3 && TX direct step 3
	{
		m_ACKEvent.Cancel();
		MlmeDisassociateConfirmParams param;
		param.DeviceAddrMode = params.DeviceAddrMode;
		param.DeviceAddress = params.DeviceAddress;
		param.DevicePANId = params.DevicePANId;
		if(!m_ACK_received)
			param.status =  IEEE_802_15_4_NO_ACK;
		else
			param.status = IEEE_802_15_4_SUCCESS;
		if(params.DisassociateReason == 0x01)	// this node is the coordinator
		{
			//the coordinator consider the device disassociated so it should be removed from the associatedDeviceList
			this->GetObject<LrWpanAssociatedDevice>()->removeAssociateDevice(m_MlmeDisassociateRequestParams.DeviceAddress,m_MlmeDisassociateRequestParams.DeviceAddrMode);
		}
		else			//this node is not the coordinator, we set the MACAttributes to their original values
		{
			m_macPIBattributes.macAssociatedPANCoord = def_MacPIBattributes.macAssociatedPANCoord;;
			m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
			m_macPIBattributes.macCoordShortAddress = def_MacPIBattributes.macCoordShortAddress;
			m_macPIBattributes.macCoordExtendedAddress =  def_MacPIBattributes.macCoordExtendedAddress;
			m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
		}
		resetUserCase();
		if(!m_mlmeDisassociateConfirmCallback.IsNull())
			m_mlmeDisassociateConfirmCallback(param);
		else
			NS_LOG_ERROR("the m_mlmeDisassociateConfirmCallback has not been initialized");
		break;
	}
	}
}



void
LrWpanMac::MlmeAssociateResponse(MlmeAssociateResponseParams params)
{
	NS_LOG_FUNCTION(this);
	m_userCase = Mlme_Associate_Response;
	if(params.SecurityLevel > 0)
	{
		//todo implement security for the frame
	}

	switch (m_step) {
	case 0:
	{
		m_MlmeCommStatusIndicationParams.DstAddr = params.DeviceAddress.operator ns3::Address();
		m_MlmeCommStatusIndicationParams.DstAddrMode = EXT_ADDR;
		m_MlmeCommStatusIndicationParams.PANId = m_macPIBattributes.macPANId;
		m_MlmeCommStatusIndicationParams.SecurityLevel = params.SecurityLevel;
		m_MlmeCommStatusIndicationParams.SrcAddr = m_selfExt.operator ns3::Address();
		m_MlmeCommStatusIndicationParams.SrcAddrMode = EXT_ADDR;
		//we check the transactionList for a free spot
		NS_ASSERT_MSG(this->GetObject<LrWpanTransactionList>(),
				"the transaction list has not been initialized");
		NS_ASSERT_MSG(this->GetObject<LrWpanTransactionList>(),"transactionList not initialized");
		if(this->GetObject<LrWpanTransactionList>()->isfull())
		{
			resetUserCase();
			m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_TRANSACTION_OVERFLOW;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			else
				NS_LOG_ERROR("mlmeCommStatusIndicationCallback has not been defined");
			return;
		}
		//we verify the validity of the input parameters
		if((params.status != IEEE_802_15_4_PAN_ACCESS_DENIED) &&
				(params.status != IEEE_802_15_4_PAN_AT_CAPACITY) &&
				(params.status != IEEE_802_15_4_ASSOCIATION_SUCCESSFULL))
		{
			resetUserCase();
			m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			else
				NS_LOG_ERROR("mlmeCommStatusIndicationCallback has not been defined");
			return;
		}
		//we start the associate response effectively
		m_step ++;
		m_MlmeAssociateResponseParams.AssocShortAddress = params.AssocShortAddress;
		m_MlmeAssociateResponseParams.DeviceAddress = params.DeviceAddress;
		m_MlmeAssociateResponseParams.SecurityLevel = params.SecurityLevel;
		m_MlmeAssociateResponseParams.status = params.status;
		LrWpanMacHeader RespCmdHdr;
		uint8_t payload[4];
		payload[0] = 0x02;				//0x02 represents the associate response command
		uint8_t assocBuffer[2];			// a buffer containing the assocshortAddress
		params.AssocShortAddress.CopyTo(assocBuffer);
		payload[1] = assocBuffer[0];
		payload[2] = assocBuffer[1];
		payload[3] = params.status; 	// the status is stored in the buffer
		Ptr < Packet > pkt = Create<Packet>(payload,4);
		MlmeconstructCommandHeader(pkt,&RespCmdHdr,EXT_ADDR,m_macPIBattributes.macPANId,params.DeviceAddress.operator ns3::Address(),
				EXT_ADDR,m_macPIBattributes.macPANId,m_selfExt,params.SecurityLevel,false,true);
		this->GetObject<LrWpanTransactionList>()->add(pkt);
	}
	case 1:			//we wait for macTransactionPersistentTime
	{
		m_step ++;
		double a = (double)(m_macPIBattributes.macTransactionPersistenceTime);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time time4Transaction = Seconds(a / b);
		m_transactionEvent = Simulator::Schedule(time4Transaction, &LrWpanMac::MlmeAssociateResponse, this, m_MlmeAssociateResponseParams);
		break;
	}
	case 2:				//we search into the transactionList
	{
		//the transaction we look for should be the first one in the list
		bool found = this->GetObject<LrWpanTransactionList>()->search(params.DeviceAddress.operator ns3::Address(),EXT_ADDR);
		if(found)
		{
			this->GetObject<LrWpanTransactionList>()->cancelTransaction();

			m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_TRANSACTION_EXPIRED;
			resetUserCase();
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			else
				NS_LOG_ERROR("the mlmeCommStatusIndication has not been initialized");
			return;
		}
		else{
			m_step++;
			NS_LOG_DEBUG("the packet has been sent from the transaction list");
		}

	}
	case 3:
	{
		m_step++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time time4ACK = Seconds(a / b);
		m_ACK_received = false;
		m_ACKEvent = Simulator::Schedule(time4ACK, &LrWpanMac::MlmeAssociateResponse, this, m_MlmeAssociateResponseParams);
		break;
	}
	case 4:
	{
		if(m_ACK_received)
		{
			m_ACKEvent.Cancel();
			if(params.status == IEEE_802_15_4_ASSOCIATION_SUCCESSFULL)
			{
				NS_ASSERT_MSG(this->GetObject<LrWpanAssociatedDevice>(),"LrwpanAssociatedDevice not intialized");
				this->GetObject<LrWpanAssociatedDevice>()->addAssociateDevice(params.AssocShortAddress,params.DeviceAddress);
			}
			resetUserCase();

			m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_ASSOCIATION_SUCCESSFULL;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			else
				NS_LOG_ERROR("the mlmeCommStatusIndication has not been initialized");
			//add resetUsercase
		}
		else
		{
			resetUserCase();

			m_MlmeCommStatusIndicationParams.status = IEEE_802_15_4_NO_ACK;
			if(!m_mlmeCommStatusIndicationCallback.IsNull())
				m_mlmeCommStatusIndicationCallback(m_MlmeCommStatusIndicationParams);
			else
				NS_LOG_ERROR("the mlmeCommStatusIndication has not been initialized");
			//add resetUsercase
		}
		break;
	}

	default:
		break;
	}

}

void LrWpanMac::MlmeStartRequest(MlmeStartRequestParams params)
{
	//set the MPIB value
	//as  we don(t use the beacon mode yet nothing
	MlmeStartConfirmparams param;
	bool win = false;
	if(params.Pancoordinator == true && params.beaconOrder == 15)		//we create a new non beacon enabled PAN
	{
		if(params.panId != 0xffff)
		{
			win = true;
			m_macPIBattributes.macPANId = params.panId;
		}
		else{
			param.status = IEEE_802_15_4_INVALID_PARAMETER;
		}
		m_macPIBattributes.macCoordExtendedAddress = m_selfExt;
		m_macPIBattributes.macAssociationPermit = true;
		m_macPIBattributes.macShortAddress = Mac16Address::Allocate();
		m_macPIBattributes.macCoordShortAddress = m_macPIBattributes.macShortAddress ;
		m_tmpPhyPIBattributes.phyCurrentChannel = params.logicalChannel;
		m_phy->PlmeSetAttributeRequest(phyCurrentChannel, &m_tmpPhyPIBattributes);
		m_macPIBattributes.macBeaconOrder = params.beaconOrder;
		if(win && m_macPIBattributes.macShortAddress == Mac16Address("ff:ff"))
		{
			win = false;
			param.status = IEEE_802_15_4_NO_SHORT_ADDRESS;
		}
		if(win && PlmeAttributeConfirmStatus == IEEE_802_15_4_PHY_INVALID_PARAMETER)
		{
			win = false;
			param.status = IEEE_802_15_4_INVALID_PARAMETER;
		}
		if(win && params.beaconOrder > 15)
		{
			win = false;
			param.status = IEEE_802_15_4_INVALID_PARAMETER;
		}
		if(!win)			//we reset the value
		{
			m_macPIBattributes.macShortAddress = def_MacPIBattributes.macShortAddress;
			m_macPIBattributes.macPANId = def_MacPIBattributes.macPANId;
			m_macPIBattributes.macCoordShortAddress = m_macPIBattributes.macCoordShortAddress ;
			m_macPIBattributes.macAssociationPermit = false;
			m_macPIBattributes.macBeaconOrder = def_MacPIBattributes.macBeaconOrder;
		}
		else{
			Ptr<LrWpanAssociatedDevice> m_associateDevice = CreateObject<LrWpanAssociatedDevice>();
			Ptr<LrWpanTransactionList> m_transactionList = CreateObject<LrWpanTransactionList>();
			this->AggregateObject(m_associateDevice);
			this->AggregateObject(m_transactionList);
			param.status = IEEE_802_15_4_SUCCESS;
		}
	}
	if(!m_mlmeStartConfirmCallback.IsNull())
		m_mlmeStartConfirmCallback(param);
	else
		NS_LOG_ERROR("the m_mlmeStartConfirmCallback is not initialized");
}

void
LrWpanMac::MlmeconstructCommandHeader(Ptr<Packet> pkt, LrWpanMacHeader *macHdr, LrWpanAddressMode DstAddrMode, uint16_t DstPanId, Address DstAddr,
		LrWpanAddressMode SrcAddrMode, uint16_t SrcPanId, Address SrcAddr, uint8_t SecurityLevel, bool FrmPending, bool AckReq)
{
	NS_LOG_FUNCTION(this);
	macHdr->SetSeqNum((uint8_t)m_macPIBattributes.macDSN.GetValue());
	m_macPIBattributes.macDSN ++;
	if (m_macPIBattributes.macDSN > SequenceNumber16 (255))
	{
		m_macPIBattributes.macDSN = m_macPIBattributes.macDSN - SequenceNumber16 (255);
	}
	macHdr->SetType(LrWpanMacHeader::LRWPAN_MAC_COMMAND);
	switch (DstAddrMode) {
	case SHORT_ADDR:
		macHdr->SetDstAddrMode(SHORT_ADDR);
		macHdr->SetDstAddrFields(DstPanId,Mac16Address::ConvertFrom(DstAddr));
		break;
	case EXT_ADDR:
		macHdr->SetDstAddrMode(EXT_ADDR);
		macHdr->SetDstAddrFields(DstPanId,Mac64Address::ConvertFrom(DstAddr));
		break;
	case NO_PANID_ADDR:
		macHdr->SetDstAddrMode(NO_PANID_ADDR);
		break;
	default:
		NS_LOG_ERROR("AddressMode not available");
		break;
	}
	switch (SrcAddrMode) {
	case SHORT_ADDR:
	{
		macHdr->SetSrcAddrMode(SHORT_ADDR);
		if(SrcPanId == DstPanId)
		{
			macHdr->SetPanIdComp();
			macHdr->SetSrcAddrFields(0,Mac16Address::ConvertFrom(SrcAddr));
		}
		else{
			macHdr->SetNoPanIdComp();
			macHdr->SetSrcAddrFields(SrcPanId,Mac16Address::ConvertFrom(SrcAddr));
		}
		break;
	}
	case EXT_ADDR:
	{
		macHdr->SetSrcAddrMode(EXT_ADDR);
		if(SrcPanId == DstPanId)
		{
			macHdr->SetPanIdComp();
			macHdr->SetSrcAddrFields(0,Mac64Address::ConvertFrom(SrcAddr));
		}
		else{
			macHdr->SetNoPanIdComp();
			macHdr->SetSrcAddrFields(SrcPanId,Mac64Address::ConvertFrom(SrcAddr));
		}
		break;
	}
	case NO_PANID_ADDR:
		macHdr->SetDstAddrMode(NO_PANID_ADDR);
		break;
	default:
		NS_LOG_ERROR("AddressMode not available");
		break;
	}
	if(SecurityLevel != 0)
		macHdr->SetSecEnable();
	else
		macHdr->SetSecDisable();
	if(AckReq)
		macHdr->SetAckReq();
	else
		macHdr->SetNoAckReq();
	if(FrmPending)
		macHdr->SetFrmPend();
	else
		macHdr->SetNoFrmPend();
	LrWpanMacTrailer macTrl;
	pkt->AddHeader(*macHdr);
	pkt->AddTrailer(macTrl);
}

void
LrWpanMac::addToPktBuffer(Ptr<Packet> pkt,uint8_t msduHandle)
{
	TxQueueElement *txQElement = new TxQueueElement;
	txQElement->txQPkt = pkt;
	txQElement->txQMsduHandle = msduHandle;
	if (m_txQueue.empty ())
	{
		m_txPkt = txQElement->txQPkt->Copy ();
		m_txQueue.push_front (txQElement); // the first packet in the queue is currently worked on
		LrWpanMacHeader tmp;
		Ptr<Packet>tmpPkt = pkt->Copy();
		tmpPkt->RemoveHeader(tmp);
		//ACK packet should be set without using the CSMA
		if(tmp.IsAcknowledgment())
		{
			double a = (double)(LrWpanPhy::aTurnaroundTime);
			double b = (double)(m_phy->GetDataOrSymbolRate(false));
			Time time2wait = Seconds(a / b);
			Simulator::Schedule(time2wait,&LrWpanMac::SetLrWpanMacState,this,CHANNEL_IDLE);
		}
		else
		{
			// Start CCA process for this packet
			Simulator::ScheduleNow (&LrWpanCsmaCa::Start, m_csmaCa);
		}
		tmpPkt = 0;
	}
	else
	{
		// if queue is not empty put this packet at the end of Tx queue
		m_txQueue.push_back (txQElement);
	}
}
bool
LrWpanMac::MacFrameFiltering(Ptr<Packet> pkt)
{
	// from sec 7.5.6.2 Reception and rejection, Std802.15.4-2006
	// level 1 filtering, test FCS field and reject if frame fails
	// level 2 filtering if promiscuous mode pass frame to higher layer otherwise perform level 3 filtering
	// level 3 filtering accept frame
	// if Frame type and version is not reserved, and
	// if there is a dstPanId then dstPanId=m_macPanId or broadcastPanI, and
	// if there is a shortDstAddr then shortDstAddr =shortMacAddr or broadcastAddr, and
	// if beacon frame then srcPanId = m_macPanId
	// if only srcAddr field in Data or Command frame,accept frame if srcPanId=m_macPanId

	//we add an extra set of condition to deal with ACK packets
	// the sequence number of the ACK should match the one of the previous packet
	bool acceptFrame;
	Ptr<Packet> copypkt = pkt->Copy();
	m_macPromiscRxTrace (copypkt);
	// XXX no rejection tracing (to macRxDropTrace) being performed below
	LrWpanMacHeader receivedMacHdr;
	pkt->RemoveHeader (receivedMacHdr);
	LrWpanMacTrailer receivedMacTrailer;
	pkt->RemoveTrailer (receivedMacTrailer);
	if(receivedMacHdr.IsAcknowledgment())			//case of an ACK packet
	{
		//we check the sequence number
		if(receivedMacHdr.GetSeqNum() == m_macPIBattributes.macDSN.GetValue()-1)
			acceptFrame = true;
		else if(receivedMacHdr.GetSeqNum() == ((receivedMacHdr.GetSeqNum()+1) - SequenceNumber16(255).GetValue()))
			acceptFrame = true;
		else
			acceptFrame = false;
		return acceptFrame;
	}

	if (m_macPIBattributes.macPromiscuousMode)
	{
		NS_LOG_DEBUG("promiscuousMode activated, we forward up ");
		acceptFrame = true;
		return acceptFrame;
	}
	else
	{
		//level 3 frame filtering
		acceptFrame = (receivedMacHdr.GetType () != LrWpanMacHeader::LRWPAN_MAC_RESERVED);

		if (acceptFrame)
		{
			acceptFrame = (receivedMacHdr.GetFrameVer () <= 1);
		}
		if (acceptFrame
				&& (receivedMacHdr.GetDstAddrMode () > 1))
		{
			acceptFrame = receivedMacHdr.GetDstPanId () == m_macPIBattributes.macPANId
					|| receivedMacHdr.GetDstPanId () == 0xffff;
		}

		if (acceptFrame
				&& (receivedMacHdr.GetDstAddrMode () == 2))
		{
			acceptFrame = receivedMacHdr.GetShortDstAddr () == m_macPIBattributes.macShortAddress
					|| receivedMacHdr.GetShortDstAddr () == Mac16Address ("ff:ff");        // check for broadcast addrs
		}
		if (acceptFrame
				&& (receivedMacHdr.GetDstAddrMode () == 3))
		{
			acceptFrame = (receivedMacHdr.GetExtDstAddr () == m_selfExt);
		}

		if (acceptFrame
				&& (receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_BEACON))
		{
			if (m_macPIBattributes.macPANId == 0xffff)
			{
				acceptFrame = true;
			}
			else
			{
				acceptFrame = receivedMacHdr.GetSrcPanId () == m_macPIBattributes.macPANId;
			}
		}

		if (acceptFrame && receivedMacHdr.GetDstPanId() == 0
				&& ((receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_DATA)
						|| (receivedMacHdr.GetType () == LrWpanMacHeader::LRWPAN_MAC_COMMAND))
						&& (receivedMacHdr.GetSrcAddrMode () > 1))
		{
			acceptFrame = receivedMacHdr.GetSrcPanId () == m_macPIBattributes.macPANId;

		}

		if (acceptFrame)
		{
			m_macRxTrace (copypkt);

		}
		else
		{
			m_macRxDropTrace (copypkt);
			pkt = 0;
		}
		return acceptFrame;
	}
}

void
LrWpanMac::MlmeScanRequest(MlmeScanRequestParams params)
{
	NS_LOG_FUNCTION(this);
	if(params.SecurityLevel > 0)
	{
		//todo implement security for the frame
	}
	//we save the input parameters for further uses
	m_MlmeScanRequestParams.ChannelPage = params.ChannelPage;
	m_MlmeScanRequestParams.ScanChannels = params.ScanChannels;
	m_MlmeScanRequestParams.ScanDuration = params.ScanDuration;
	m_MlmeScanRequestParams.ScanType =  params.ScanType;
	m_MlmeScanRequestParams.SecurityLevel = params.SecurityLevel;
	//return parameter for the MlmeScanconfirmCallback
	MlmeScanConfirmParams returnParam;
	returnParam.ChannelPage = params.ChannelPage;
	returnParam.ScanType = params.ScanType;
	returnParam.UnscannedChannels = params.ScanChannels;
	returnParam.status = IEEE_802_15_4_INVALID_PARAMETER;

	//we check first the parameters
	if(params.ChannelPage > 31 || params.ChannelPage != 0)
	{
		if(params.ChannelPage != 0)
			NS_LOG_ERROR("2.4 Ghz PHY,setup only for page 0");
		else
			NS_LOG_ERROR("Non valid Page number for this PHY");
		if(!m_mlmeScanConfirmCallback.IsNull())
			m_mlmeScanConfirmCallback(returnParam);
		else
			NS_LOG_ERROR("m_mlmeScanConfirmCallback not initialized");
		return;
	}
	if(params.ScanDuration > 14)
	{
		NS_LOG_ERROR("Non valid ScanDuration input");
		if(!m_mlmeScanConfirmCallback.IsNull())
			m_mlmeScanConfirmCallback(returnParam);
		else
			NS_LOG_ERROR("m_mlmeScanConfirmCallback not initialized");
		return;
	}
	if(params.ScanType > 3)
	{
		NS_LOG_ERROR("Non valid ScanType input");
		if(!m_mlmeScanConfirmCallback.IsNull())
			m_mlmeScanConfirmCallback(returnParam);
		else
			NS_LOG_ERROR("m_mlmeScanConfirmCallback not initialized");
		return;
	}
	//the parameters are valid
	m_userCase =  Mlme_Scan_Request;
	switch (params.ScanType)
	{
	case 3:				//orphan scan
	{
		switch (m_step)
		{
		static uint8_t count = 5 + 1;				//we start checking the scanChannel parameter, we start at five because the 5 first bit represent the page
		case 0:
		{
			if(count >32)
			{
				resetUserCase();
				returnParam.status = IEEE_802_15_4_NO_LIMIT_REACHED;
				if(!m_mlmeScanConfirmCallback.IsNull())
					m_mlmeScanConfirmCallback(returnParam);
				else
					NS_LOG_ERROR("m_mlmeScanConfirmCallback not initialized");
				return;
			}
			if((params.ScanChannels & (1 << (32 - count))) == 0)		//if channel 'count' = 0
			{
				count ++;
				m_step = 0;
				MlmeScanRequest(m_MlmeScanRequestParams);		//start again with count + 1
				return;
			}
			else												//if channel 'count' = 1
			{
				if(!m_phy->ChannelSupported(count))
				{
					NS_LOG_INFO(this << "the channel " << count << " is not supported ");
					count ++;
					m_step = 0;
					MlmeScanRequest(m_MlmeScanRequestParams);		//start again with count + 1
					return;
				}
				else
				{
					NS_LOG_DEBUG(this << "channel " << count <<" is supported, we start scanning on it");
					m_step ++;
					MlmeScanRequest(m_MlmeScanRequestParams);
					return;
				}
			}
			break;
		}
		case 1:
		{
			// we set to 0 the 'count' bit of unscanned channel
			returnParam.UnscannedChannels = returnParam.UnscannedChannels & (~(1 << (32 - count)));
			m_step ++;
			m_tmpPhyPIBattributes.phyCurrentChannel = count;
			m_phy->PlmeSetAttributeRequest(phyCurrentChannel,&m_tmpPhyPIBattributes);
			LrWpanMacHeader OrphanCmdHdr;
			uint8_t payload = 0x06;			//0x06 represents the Orphan notification
			Ptr<Packet> pkt = Create<Packet>(&payload,1);
			MlmeconstructCommandHeader(pkt,&OrphanCmdHdr,SHORT_ADDR,0xffff,Mac16Address("ff:ff").operator ns3::Address(),
					EXT_ADDR,0xffff,m_selfExt,params.SecurityLevel,false,false);
			addToPktBuffer(pkt,0);
			break;
		}
		case 2:
		{
			m_step ++;
			m_CmdReceived = false;
			double a = (double)m_macPIBattributes.macMaxFrameTotalWaitTime;			//maxResponseTIme should be used but is too short
			double b = (double)m_phy->GetDataOrSymbolRate(false);
			Time Wait4Cmd = Seconds(a/b);
			m_orphanEvent = Simulator::Schedule(Wait4Cmd,&LrWpanMac::MlmeScanRequest,this,m_MlmeScanRequestParams);
			break;
		}
		case 3:
		{
			if(m_CmdReceived)
			{
				m_orphanEvent.Cancel();
				resetUserCase();
				returnParam.status = IEEE_802_15_4_SUCCESS;
				if(!m_mlmeScanConfirmCallback.IsNull())
					m_mlmeScanConfirmCallback(returnParam);
				else
					NS_LOG_ERROR("m_mlmeScanConfirmCallback is not initialized");
			}
			else
			{
				count ++;
				m_step = 0;
				MlmeScanRequest(m_MlmeScanRequestParams);		//start again with count + 1
				return;
			}
			break;
		}

		}
	}
	case 1:
	{
		//todo
		break;
	}
	case 2:
	{
		//todo
		break;
	}



	default:
		break;
	}
}


void
LrWpanMac::sendACKnowledgment(LrWpanMacHeader * receivedMacHeader,bool isPendingNeeded)
{
	NS_LOG_FUNCTION(this);
	LrWpanMacHeader ACKHdr;
	ACKHdr.SetNoAckReq();
	ACKHdr.SetSrcAddrMode(NO_PANID_ADDR);
	ACKHdr.SetDstAddrMode(NO_PANID_ADDR);
	ACKHdr.SetType(LrWpanMacHeader::LRWPAN_MAC_ACKNOWLEDGMENT);
	ACKHdr.SetNoPanIdComp();
	ACKHdr.SetSecDisable();
	ACKHdr.SetSeqNum(receivedMacHeader->GetSeqNum());
	Ptr < Packet > pkt = Create<Packet>(1); //1 dummy byte just because a zero payload packet would mean there is no frame pending

	// in case of an ACK to a datarequest command from a PollRequest
	// we should check the transaction list
	if(isPendingNeeded)
	{
		NS_ASSERT_MSG(this->GetObject<LrWpanTransactionList>(),"transactionList not initialized");
		if(this->GetObject<LrWpanTransactionList>()->isEmpty())
		{
			ACKHdr.SetNoFrmPend();
		}
		else{
			std::list<LrWpanTransactionList>::iterator it;
			int i;				//# of packets found
			if(receivedMacHeader->GetSrcAddrMode() == SHORT_ADDR)
				i = this->GetObject<LrWpanTransactionList>()->search(receivedMacHeader->GetShortSrcAddr().operator ns3::Address(),SHORT_ADDR);
			if(receivedMacHeader->GetSrcAddrMode() == EXT_ADDR)
				i = this->GetObject<LrWpanTransactionList>()->search(receivedMacHeader->GetExtSrcAddr().operator ns3::Address(),EXT_ADDR);
			if(i >= 1)
				ACKHdr.SetFrmPend();
			else
				ACKHdr.SetNoFrmPend();
		}
	}
	pkt->AddHeader(ACKHdr);
	LrWpanMacTrailer ACKTrl;
	pkt->AddTrailer(ACKTrl);
	if(receivedMacHeader->GetSrcAddrMode() == SHORT_ADDR)
		NS_LOG_DEBUG("the node " << m_selfExt << " start sending  the ACK packet to " << receivedMacHeader->GetShortSrcAddr());
	else
		NS_LOG_DEBUG("the node " << m_selfExt << " start sending  the ACK packet to " << receivedMacHeader->GetExtSrcAddr() );
	addToPktBuffer(pkt,0);
}

void LrWpanMac::MlmeResetRequest(MlmeResetRequestParams params)
{
	NS_LOG_FUNCTION(this);

	m_userCase = Mlme_Reset_Request;
	if(params.resetPIB)
		m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_FORCE_TRX_OFF);
	m_macPIBattributes = def_MacPIBattributes;
	m_lrWpanMacState = MAC_IDLE;
	m_txPkt = 0;
	m_userCase = Mlme_No_Case;
	m_step = 0;
	m_ACK_received = false;
	m_CmdReceived = false;
	m_DataReceived = false;
	m_framePending = false;
	Ptr<LrWpanPhy> m_phy;
	//todo complete destruction of packet in m_txqueue
	for (uint32_t i = 0; i < m_txQueue.size (); i++)
	{
		m_txQueue[i]->txQPkt = 0;
		delete m_txQueue[i];
	}
	m_txQueue.clear ();
	m_ACKEvent.Cancel();
	m_DataEvent.Cancel();
	m_transactionEvent.Cancel();
	if(this->GetObject<LrWpanTransactionList>())
	{
		this->GetObject<LrWpanTransactionList>()->Dispose();
		this->GetObject<LrWpanTransactionList>() = 0;
		Ptr<LrWpanTransactionList> newTransactionList = CreateObject<LrWpanTransactionList>();
		this->AggregateObject(newTransactionList);
	}
	if(this->GetObject<LrWpanAssociatedDevice>())
	{
		this->GetObject<LrWpanTransactionList>()->Dispose();
		this->GetObject<LrWpanTransactionList>() = 0;
		Ptr<LrWpanAssociatedDevice> newAssociateList = CreateObject<LrWpanAssociatedDevice>();
		this->AggregateObject(newAssociateList);
	}
	//this method should not fail for any reason

}
void
LrWpanMac::MlmePollRequest(MlmePollRequestParams params)
{
	NS_LOG_FUNCTION(this);
	if(params.SecurityLevel != 0)
	{
		//todo security check
	}
	switch (m_step){
	case 0:
	{
		m_userCase = Mlme_Poll_Request;
		if((params.CoordAddrMode != EXT_ADDR) && (params.CoordAddrMode != SHORT_ADDR))
		{
			MlmePollConfirmParams params;
			params.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmePollConfirmCallback.IsNull())
				m_mlmePollConfirmCallback (params);
			return;
		}
		if((params.CoordAddrMode == SHORT_ADDR)&&
				((Mac16Address::ConvertFrom(params.CoordAddress) == Mac16Address("ff:fe"))||
						(Mac16Address::ConvertFrom(params.CoordAddress) == Mac16Address("ff:ff"))))
		{
			NS_LOG_ERROR("coordinator address non valid, need an Extended address instead");
			MlmePollConfirmParams params;
			params.status = IEEE_802_15_4_INVALID_PARAMETER;
			if(!m_mlmePollConfirmCallback.IsNull())
				m_mlmePollConfirmCallback (params);
			else
				NS_LOG_ERROR("m_mlmePollConfirmCallback is not initialized");
			return;
		}
		m_step ++;
		m_MlmePollRequestParams.CoordAddrMode = params.CoordAddrMode;
		m_MlmePollRequestParams.CoordPANId = params.CoordPANId;
		m_MlmePollRequestParams.CoordAddress = params.CoordAddress;
		m_MlmePollRequestParams.SecurityLevel = params.SecurityLevel;
	}
	case 1:
	{
		m_step ++;
		//we start creating and sending the data request command
		uint8_t  payload = 0x04;
		LrWpanMacHeader CmdHdr;
		Ptr < Packet > pkt = Create<Packet>(&payload,1);
		if(m_macPIBattributes.macShortAddress == Mac16Address("ff:ff"))
		{
			NS_LOG_ERROR("the device does not seem  associated, macShortAddress == ff:ff");
			return;
		}
		if(m_macPIBattributes.macShortAddress == Mac16Address("ff:fe"))		//we should use the extended address instead
		{
			MlmeconstructCommandHeader(pkt, &CmdHdr, params.CoordAddrMode, params.CoordPANId, params.CoordAddress,
					EXT_ADDR, m_macPIBattributes.macPANId, m_selfExt.operator ns3::Address(), params.SecurityLevel,false,true);

		}else
		{
			MlmeconstructCommandHeader(pkt, &CmdHdr, params.CoordAddrMode, params.CoordPANId, params.CoordAddress,
					SHORT_ADDR, m_macPIBattributes.macPANId, m_macPIBattributes.macShortAddress.operator ns3::Address(), params.SecurityLevel,false,true);
		}
		addToPktBuffer(pkt,0);
		break;
	}
	case 2:
	{
		m_step++;
		double a = (double)(m_macPIBattributes.macAckWaitDuration);
		double b = (double)(m_phy->GetDataOrSymbolRate(false));
		Time wait4ACK = Seconds(a / b);
		m_ACK_received = false;
		m_framePending = false;
		m_ACKEvent = Simulator::Schedule(wait4ACK,&LrWpanMac::MlmePollRequest,this,m_MlmePollRequestParams);
		break;
	}
	case 3:
	{
		if(!m_ACK_received)//ack failed
		{
			if(m_numCmdRetry <= m_macPIBattributes.macMaxFrameRetries)
			{
				NS_LOG_DEBUG("ACK not received, we retransmit");
				m_step = 1;
				m_numCmdRetry++;
				m_ACK_received = false;
				m_framePending = false;
				MlmePollRequest(m_MlmePollRequestParams);

			}else
			{
				NS_LOG_DEBUG("ACK not received, can't retransmit ,return NO ACK");
				resetUserCase();
				MlmePollConfirmParams params;
				params.status = IEEE_802_15_4_NO_ACK;
				if(!m_mlmePollConfirmCallback.IsNull())
				{
					m_mlmePollConfirmCallback (params);
				}
				else{
					NS_LOG_ERROR("mlmePollConfirmCallback not initialized");
				}
				return;
			}
		}
		else			//ack received
		{
			m_ACKEvent.Cancel();
			if(!m_framePending)
			{
				NS_LOG_DEBUG("ACK received, No pending packet");
				resetUserCase();
				MlmePollConfirmParams params;
				params.status = IEEE_802_15_4_NO_DATA;
				if(!m_mlmePollConfirmCallback.IsNull())
				{
					m_mlmePollConfirmCallback (params);
				}
				else{
					NS_LOG_ERROR("mlmePollConfirmCallback not initialized");
				}
			}
			else{
				NS_LOG_DEBUG("ACK received, Incoming pending packet");
				m_step ++;
				m_framePending = false;
				m_ACK_received = false;
				m_DataReceived = false;
				m_numCmdRetry = 0;
				double a = (double)(m_macPIBattributes.macMaxFrameTotalWaitTime);
				double b = (double)(m_phy->GetDataOrSymbolRate(false));
				Time Wait4Frame = Seconds(a / b);
				m_DataEvent = Simulator::Schedule(Wait4Frame, &LrWpanMac::MlmePollRequest, this, m_MlmePollRequestParams);
			}
		}
		break;
	}
	case 4:
	{
		if(!m_DataReceived)
		{
			NS_LOG_DEBUG("No DataFrame Received or 0 Payload packet or Command Frame ");
			resetUserCase();
			MlmePollConfirmParams params;
			params.status = IEEE_802_15_4_NO_DATA;
			if(!m_mlmePollConfirmCallback.IsNull())
				m_mlmePollConfirmCallback(params);
			else
				NS_LOG_ERROR("mlmePollConfirmCallback not initialized");
		}
		else
		{
			NS_LOG_DEBUG("Valid DataFrame received");
			m_DataEvent.Cancel();
			MlmePollConfirmParams params;
			params.status = IEEE_802_15_4_SUCCESS;

			if(!m_mlmePollConfirmCallback.IsNull())
				m_mlmePollConfirmCallback (params); //we send an MCPS indication too in the pddataconfirm
			else
				NS_LOG_ERROR("mlmePollConfirmCallback is not initialized");
			//if the frame pending field of the packet we received is one, there is another packet pending in the transactionList
			if(m_framePending)
			{
				//we reset the variables and we recall the method
				resetUserCase();
				MlmePollRequest(m_MlmePollRequestParams);
			}
			else
			{
				resetUserCase();
			}
		}
		break;
	}
	}
}
void
LrWpanMac::DataResponse(LrWpanMacHeader  receivedHdr)
{

	NS_LOG_FUNCTION(this);
	NS_ASSERT_MSG(this->GetObject<LrWpanTransactionList>(),"transactionList not initialized");
	if(this->GetObject<LrWpanTransactionList>()->isEmpty())
	{
		NS_LOG_ERROR("the transactionList is empty");
		return;
	}

	std::list<LrWpanTransactionList>::iterator it;
	//now i should check in my pending list to see if there is a packet pending for
	//the device which send the packet
	int i;				//# of packets found
	if(receivedHdr.GetSrcAddrMode() == SHORT_ADDR)
		i = this->GetObject<LrWpanTransactionList>()->search(receivedHdr.GetShortSrcAddr().operator ns3::Address(),SHORT_ADDR);
	if(receivedHdr.GetSrcAddrMode() == EXT_ADDR)
		i = this->GetObject<LrWpanTransactionList>()->search(receivedHdr.GetExtSrcAddr().operator ns3::Address(),EXT_ADDR);
	if(i >= 1)
	{
			m_transactionEvent.Cancel();
		NS_LOG_DEBUG("we found a packet in the pending list of " << m_selfExt );
		Ptr<Packet> pkt;
		if(i == 1)
		{
			if(receivedHdr.GetSrcAddrMode() == SHORT_ADDR)
				pkt = this->GetObject<LrWpanTransactionList>()->get(receivedHdr.GetShortSrcAddr().operator ns3::Address(),SHORT_ADDR);
			if(receivedHdr.GetSrcAddrMode() == EXT_ADDR)
				pkt = this->GetObject<LrWpanTransactionList>()->get(receivedHdr.GetExtSrcAddr().operator ns3::Address(),EXT_ADDR);
		}
		else			//we have more than one packet for the same device in the transactionList, we should set the pending to one
		{
			if(receivedHdr.GetSrcAddrMode() == SHORT_ADDR)
				pkt = this->GetObject<LrWpanTransactionList>()->Update(receivedHdr.GetShortSrcAddr().operator ns3::Address(),SHORT_ADDR);
			if(receivedHdr.GetSrcAddrMode() == EXT_ADDR)
				pkt = this->GetObject<LrWpanTransactionList>()->Update(receivedHdr.GetExtSrcAddr().operator ns3::Address(),EXT_ADDR);
		}
		addToPktBuffer(pkt,0);
	}
	else
	{
		NS_LOG_DEBUG("no packet Pending");
	}
}
}// namespace ns3
